docs/oauth_mcpproxy_bug.md
This document describes OAuth token management bugs discovered during OAuth E2E testing and their fixes.
After a successful OAuth login, if the access token expires and mcpproxy attempts to reconnect, the server remains in "disconnected" status with error:
failed to connect: all authentication strategies failed, last error: OAuth authorization required - deferred for background processing
When mcpproxy reconnects to an OAuth-protected server:
token_expires_at in the past)Added HasPersistedToken() function in internal/oauth/config.go:
hasRefreshToken and isExpired flagsAdded token refresh retry logic in internal/upstream/core/connection.go:
Enhanced logging to distinguish between token scenarios:
Run OAuth E2E tests with short token TTL:
go run ./tests/oauthserver/cmd/server -port 9000 -access-token-ttl=30s
# Token should auto-refresh without browser re-authentication
Multiple OAuth flows may run concurrently, causing state corruption:
WARN | ⚠️ OAuth is already in progress, clearing stale state and retrying
INFO | 🧹 Clearing OAuth state | {"was_in_progress": true, "was_completed": false}
The OAuth state machine doesn't properly coordinate multiple reconnection attempts:
Implemented OAuthFlowCoordinator in internal/oauth/coordinator.go:
StartFlow() returns ErrFlowInProgress if flow already activeWaitForFlow() allows goroutines to wait for completionEndFlow() notifies all waiters of completionIntegrated coordinator into OAuth strategies:
tryOAuthAuth() and trySSEOAuthAuth() now use coordinatorAdded correlation IDs for flow traceability:
Trigger rapid reconnections and verify single OAuth flow:
# Multiple reconnection attempts should result in single OAuth flow
# Second goroutine should log "waiting for OAuth flow to complete"
Browser opening is rate-limited, preventing OAuth flow from completing:
WARN | Browser opening rate limited, skipping
The browser rate limiter prevents opening multiple browser windows in quick succession. However, when combined with Bug 2 (race condition), this can prevent any OAuth flow from completing.
Browser rate limiting is already per-server:
Client instance has its own lastOAuthTimestampCombined with Bug 2 fix:
Manual OAuth flows bypass rate limiting:
mcpproxy auth login sets context flag to bypass rate limitBrowser should open for each unique server's OAuth flow without interference.
internal/oauth/coordinator.go - OAuth flow coordinator for race condition preventioninternal/oauth/correlation.go - Correlation ID generation and context propagationinternal/oauth/logging.go - Enhanced OAuth logging with token redactioninternal/upstream/core/connection.go - Token refresh retry, flow coordinator integrationinternal/oauth/config.go - HasPersistedToken(), GetPersistedRefreshToken()internal/oauth/persistent_token_store.go - Enhanced token metadata logginginternal/oauth/discovery.go - Consistent request/response loggingAll fixes are covered by unit tests:
internal/oauth/coordinator_test.gointernal/oauth/correlation_test.gointernal/oauth/logging_test.goRun verification:
# Unit tests
go test -race ./internal/oauth/... -v
# E2E tests
./scripts/run-oauth-e2e.sh
internal/upstream/core/connection.go - OAuth authentication logicinternal/upstream/managed/client.go - Managed client reconnectioninternal/oauth/ - OAuth configuration and flow managementtests/oauthserver/ - OAuth test server for reproductionspecs/008-oauth-token-refresh/ - Feature specification