OAuth callback flow broken for Claude.ai — proxy does not forward auth code to client redirect_uri
- Dominant language
- Go
- Stars
- 140
- Forks
- 45
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 2
Description
## Problem
When deploying AKS MCP with OAuth behind a TLS-terminating ingress (Envoy Gateway) and connecting via Claude.ai, the OAuth flow fails after the user successfully authenticates with Azure AD.
**Root cause:** The AKS MCP OAuth proxy intercepts the `/authorize` request correctly, but the `/oauth/callback` handler attempts to complete the token exchange itself rather than forwarding the auth code back to the client's (Claude's) registered redirect URI.
Claude registers `https://claude.ai/api/mcp/auth_callback` as its redirect URI via dynamic client registration. The proxy should:
1. Rewrite `redirect_uri` to its own callback at `/authorize` time, stashing Claude's original redirect URI in the `state` parameter
2. On receiving the callback from Azure AD, forward the code onwards to Claude at `https://claude.ai/api/mcp/auth_callback?code=...&state=...`
3. Proxy the `/token` request, rewriting `redirect_uri` back to the proxy's callback
Instead, the server attempts to complete the exchange itself, which means Claude never receives the auth code and fails with `code: Field required`.
## Reference
This proxy pattern is documented and working here:
https://dhanushgcse.github.io/MCPAuthViaMicrosoftEntra/
Related PR: https://github.com/Azure/aks-mcp/pull/364
## Evidence
After completing Microsoft login, the browser lands at `claude.ai/api/mcp/auth_callback` with:
```json
{"type":"error","error":{"type":"invalid_request_error","message":"code: Field required"}}
```
Pod logs show the flow stops after redirecting to Azure AD with no subsequent `/oauth/callback` entry:
`
time="14:50:03" level=debug msg="Registering config prompts (query_aks_cluster_metadata_from_kubeconfig)"
time="14:50:03" level=debug msg="Registering health prompts (check_cluster_health)"
time="14:50:03" level=info msg="AKS MCP service initialization completed successfully"
time="14:50:03" level=info msg="AKS MCP version: "
time="14:50:03" level=info msg="Registering OAuth endpoints..."
time="14:50:03" level=info msg="Streamable HTTP server listening on 0.0.0.0:8000"
time="14:50:03" level=info msg="MCP endpoint available at: http://0.0.0.0:8000/mcp"
time="14:50:03" level=info msg="Send POST requests to /mcp to initialize session and obtain Mcp-Session-Id"
time="14:50:03" level=info msg="OAuth authentication enabled - Bearer token required for MCP endpoint"
time="14:50:03" level=info msg="OAuth metadata available at: http://0.0.0.0:8000/.well-known/oauth-protected-resource"
time="14:52:18" level=debug msg="OAuth DEBUG - Missing authorization header for POST /mcp"
time="14:52:18" level=error msg="Authentication FAILED - handling error"
time="14:52:18" level=error msg="MIDDLEWARE ERROR: Error response sent"
time="14:52:30" level=debug msg="OAuth DEBUG: Received request for protected resource metadata: GET /.well-known/oauth-protected-resource"
time="14:52:30" level=debug msg="OAuth DEBUG: Building protected resource metadata for URL: https://aks-mcp./mcp (transport: streamable-http)"
time="14:52:30" level=debug msg="OAuth DEBUG: Successfully generated protected resource metadata with 1 authorization servers"
time="14:52:30" level=debug msg="OAuth DEBUG: Received request for authorization server metadata: GET /.well-known/oauth-authorization-server"
time="14:52:30" level=debug msg="OAuth DEBUG: Fetching Azure AD metadata from: https://login.microsoftonline.com//v2.0/.well-known/openid-configuration"
time="14:52:30" level=debug msg="OAuth DEBUG: Successfully parsed Azure AD metadata, original grant_types_supported: []"
time="14:52:30" level=debug msg="OAuth DEBUG: Setting default grant_types_supported (was empty/nil)"
time="14:52:30" level=debug msg="OAuth DEBUG: Enforcing S256 code challenge method support (MCP requirement)"
time="14:52:30" level=debug msg="OAuth DEBUG: Final metadata prepared - grant_types_supported: [authorization_code refresh_token], response_types_supported: [code id_token code id_token id_token token], code_challenge_methods_supported: [S256]"
time="14:52:30" level=debug msg="OAuth DEBUG: Received client registration request: POST /oauth/register"
time="14:52:30" level=debug msg="OAuth DEBUG: Client registration request parsed - client_name: Claude, redirect_uris: [https://claude.ai/api/mcp/auth_callback]"
time="14:52:31" level=debug msg="OAuth DEBUG: Received authorization proxy request: GET /oauth2/v2.0/authorize"
time="14:52:31" level=debug msg="OAuth DEBUG: Removing resource parameter for Azure AD compatibility: https://aks-mcp./mcp"
time="14:52:31" level=debug msg="OAuth DEBUG: Setting final scope for Azure AD: api:///.default"
time="14:52:31" level=debug msg="OAuth DEBUG: Redirecting to Azure AD authorization endpoint: https://login.microsoftonline.com//oauth2/v2.0/authorize"
`
Contributor guide
Research direction
Start with the OAuth endpoints described in the issue, especially /oauth/register, /oauth2/v2.0/authorize, and /oauth/callback, and compare their behavior with the related PR #364. Trace the authorization-code flow from Claude.ai through Azure AD and verify that completion forwards the code to Claude's registered redirect URI while token exchange uses the proxy callback.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, go
- Domain
- api, authentication, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100