microsoft/semantic-kernel · error · ValueError
Invalid authorization code
Error message
Invalid authorization code
What it means
Raised during the OAuth token exchange step: the authorization code passed to exchange_authorization_code is not present in self.auth_codes. Authorization codes in this sample are single-use (deleted immediately after exchange at line 233) and held only in memory, so the code is rejected if it was already used, expired, or generated by a different server instance.
Source
Thrown at python/samples/demos/mcp_with_oauth/server/mcp_simple_auth/simple_auth_provider.py:212
"user_id": f"user_{secrets.token_hex(8)}",
"authenticated_at": time.time(),
}
del self.state_mapping[state]
return construct_redirect_uri(redirect_uri, code=new_code, state=state)
async def load_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: str
) -> AuthorizationCode | None:
"""Load an authorization code."""
return self.auth_codes.get(authorization_code)
async def exchange_authorization_code(
self, client: OAuthClientInformationFull, authorization_code: AuthorizationCode
) -> OAuthToken:
"""Exchange authorization code for tokens."""
if authorization_code.code not in self.auth_codes:
raise ValueError("Invalid authorization code")
# Generate MCP access token
mcp_token = f"mcp_{secrets.token_hex(32)}"
# Store MCP token
self.tokens[mcp_token] = AccessToken(
token=mcp_token,
client_id=client.client_id,
scopes=authorization_code.scopes,
expires_at=int(time.time()) + 3600,
resource=authorization_code.resource, # RFC 8707
)
# Store user data mapping for this token
self.user_data[mcp_token] = {
"username": self.settings.demo_username,
"user_id": f"user_{secrets.token_hex(8)}",
"authenticated_at": time.time(),View on GitHub (pinned to c028a0c7dc)
Solutions
- Restart the OAuth flow from the beginning to get a brand-new authorization code, and exchange it exactly once.
- Avoid server restarts between issuing and exchanging the code (in-memory store).
- Make the MCP client start a fresh authorization request after any failed token exchange rather than retrying the same code.
- Run a single server instance; do not load-balance the sample across processes.
Example fix
// Operational, not a code fix. Exchange each code exactly once: // 1. authorize -> get code // 2. exchange code -> tokens (one-shot) // 3. on any failure, restart from step 1
Defensive patterns
Strategy: validation
Validate before calling
# Exchange each authorization code exactly once; track whether it was consumed.
if code not in provider.auth_codes:
# restart the authorization flow to obtain a fresh code
raise RuntimeError('code already consumed or invalid; restart flow') Try / catch
try:
token = await provider.exchange_authorization_code(client, auth_code)
except ValueError as e:
if 'Invalid authorization code' in str(e):
# begin a new authorization request; do not retry the same code
...
raise Prevention
- Never retry a token exchange with the same code after any failure.
- Keep the server running between code issuance and exchange (in-memory store).
- Run a single server instance for the sample.
- On any token-endpoint error, restart the flow from authorization.
When it happens
Trigger: Calling the token endpoint twice with the same code (second call fails because the first deleted it); server restart wiping the in-memory auth_codes; presenting a code issued by a previous/other server instance; replaying a captured code.
Common situations: MCP client retries the token request after a transient network error (code already consumed); server restarted between authorization and token exchange; running the flow across server redeployments.
Related errors
- Invalid state parameter
- Invalid credentials
- Refresh tokens not supported
- OAuth error: {self.callback_data['error']}
- Timeout waiting for OAuth callback
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/093f7d7c15bc2739.
Report an issue: GitHub.