Azure / Azure/aks-mcp

OAuth callback flow broken for Claude.ai — proxy does not forward auth code to client redirect_uri

Open
#365 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.