Significant-Gravitas/AutoGPT · error · HTTPException
OAuth2 callback failed to exchange code for tokens: {str(e)}
Error message
OAuth2 callback failed to exchange code for tokens: {str(e)} What it means
Raised (HTTP 400) by the external OAuth complete endpoint when `handler.exchange_code_for_tokens(...)` (or the subsequent default-scopes/scope-normalization block) raises any exception. The original exception is logged as 'OAuth2 Code->Token exchange failed for provider {provider}' and its string is surfaced in the detail, so the provider's error message (invalid_grant, redirect_uri mismatch, network failure) is embedded verbatim.
Source
Thrown at autogpt_platform/backend/backend/api/external/v1/integrations.py:455
credentials = await handler.exchange_code_for_tokens(
request.code, scopes, valid_state.code_verifier
)
# Handle Linear's space-separated scopes
if len(credentials.scopes) == 1 and " " in credentials.scopes[0]:
credentials.scopes = credentials.scopes[0].split(" ")
# Check scope mismatch
if not set(scopes).issubset(set(credentials.scopes)):
logger.warning(
f"Granted scopes {credentials.scopes} for provider {provider} "
f"do not include all requested scopes {scopes}"
)
except Exception as e:
logger.error(f"OAuth2 Code->Token exchange failed for provider {provider}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"OAuth2 callback failed to exchange code for tokens: {str(e)}",
)
# Store credentials
await creds_manager.create(auth.user_id, credentials)
logger.info(f"Successfully completed external OAuth for provider {provider}")
return OAuthCompleteResponse(
credentials_id=credentials.id,
provider=credentials.provider,
type=credentials.type,
title=credentials.title,
scopes=credentials.scopes,
username=credentials.username,
state_metadata=valid_state.state_metadata,
)View on GitHub (pinned to 9c8bb5550f)
Solutions
- Read the detail message: 'invalid_grant' or 'code already redeemed' means restart the flow from authorize; 'redirect_uri mismatch' means align the callback URL used in both steps with the provider app config.
- Complete the callback immediately after the user is redirected back; never retry with the same code.
- Verify the provider OAuth app's allowed redirect URIs include the external callback origin.
- Check backend logs (`OAuth2 Code->Token exchange failed for provider ...`) for the full provider response when the detail is opaque.
Example fix
# before: retrying a consumed authorization code
POST /integrations/github/oauth/callback {"state_token": st, "code": "reused_code"} # 400
# after: get a fresh code by restarting the flow
POST /integrations/github/oauth/authorize -> user authorizes -> new code
POST /integrations/github/oauth/callback {"state_token": new_st, "code": "fresh_code"} Defensive patterns
Strategy: retry
Try / catch
try:
creds = client.post(f"/integrations/{provider}/oauth/callback", json={"state_token": state, "code": code})
except HTTPError as e:
detail = e.response.text
if "invalid_grant" in detail or "code" in detail.lower():
# auth codes are single-use & short-lived: restart the whole flow
state, login_url = client.post(f"/integrations/{provider}/oauth/authorize", json=payload).json().values()
raise RestartFlow(login_url) # send user back to provider consent
if "redirect_uri" in detail:
raise ConfigError("align callback URL with provider app settings") from e
raise Prevention
- Exchange the code for tokens as soon as the user lands on your callback (codes expire in minutes).
- Never retry a failed token exchange with the same code — restart the flow.
- Register the exact external callback URI in the provider's OAuth app settings.
When it happens
Trigger: POST `/integrations/{provider}/oauth/callback` with an expired or already-used authorization code, a redirect_uri that differs from the one used at authorize time, wrong client credentials, a provider outage/network error, or a provider response that fails parsing.
Common situations: Redeeming an auth code after the typical 5–10 minute provider TTL; retrying the callback after a first failure (codes are single-use); the platform's provider OAuth app redirect URI not covering the external callback; clock skew or revoked provider app.
Related errors
- Provider '{provider}' not found
- Server did not return an access token for the Google Drive p
- Integration with provider '{provider_name}' is not configure
- Callback URL origin is not allowed. Allowed origins: {settin
- Invalid or expired state token
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/d1517cd80d55e63b.
Report an issue: GitHub.