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

  1. Restart the OAuth flow from the beginning to get a brand-new authorization code, and exchange it exactly once.
  2. Avoid server restarts between issuing and exchanging the code (in-memory store).
  3. Make the MCP client start a fresh authorization request after any failed token exchange rather than retrying the same code.
  4. 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

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


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/093f7d7c15bc2739. Report an issue: GitHub.