Closed
Description
Problem
The thv proxy
command with remote authentication (--remote-auth
) does not handle OAuth token refresh, causing the proxy to fail once the initial access token expires (typically after 1 hour).
Root Cause
- OAuth flow is performed once at startup (line 171)
- Only the token string is extracted - the
RefreshToken
andoauth2.Token
object are discarded (lines 410-414) - Static token middleware -
createTokenInjectionMiddleware
uses a fixed token that never gets refreshed (line 503) - No expiry detection - no mechanism exists to detect token expiry or perform refresh
// Lines 410-414 in proxy.go - only token string is kept
if tokenResult.IDToken != "" {
return tokenResult.IDToken, nil
}
return tokenResult.AccessToken, nil
// Lines 503-511 - static token injection
func createTokenInjectionMiddleware(accessToken string) types.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
next.ServeHTTP(w, r)
})
}
}
Impact
- Long-running proxy instances fail after token expiration (typically 1 hour)
- Users experience authentication failures without clear indication of the cause
- Manual restart required to re-authenticate
- Poor user experience for production deployments
Current Behavior
- User starts proxy with
--remote-auth
- OAuth flow completes successfully
- Proxy works fine initially
- After ~1 hour, token expires
- All requests start failing with 401 Unauthorized
- No automatic recovery - manual restart needed
Expected Behavior
The proxy should automatically refresh tokens when they expire, maintaining continuous authentication.
Potential Solutions
Option 1: Use oauth2.Client with automatic refresh
// Store the complete oauth2.Token and oauth2.Config
// Use oauth2.Config.Client(ctx, token) which handles refresh automatically
client := oauthConfig.Client(ctx, token)
Option 2: Implement refresh logic in middleware
// Check token expiry in middleware
// Refresh token when needed
// Update Authorization header with new token
Option 3: Background token refresh goroutine
// Start a goroutine that periodically checks and refreshes tokens
// Update the middleware's token atomically
Files Affected
cmd/thv/app/proxy.go
- Main proxy logicpkg/auth/oauth/flow.go
- OAuth flow implementation (already supports refresh tokens)
Additional Context
The OAuth flow implementation in pkg/auth/oauth/flow.go
already properly handles and returns refresh tokens in the TokenResult
struct (lines 68-69), but this information is not utilized by the proxy command.
// TokenResult already includes refresh token
type TokenResult struct {
AccessToken string
RefreshToken string // This is available but unused!
TokenType string
Expiry time.Time
Claims jwt.MapClaims
IDToken string
}