Significant-Gravitas/AutoGPT · error · HTTPException
State token was not created for external OAuth flow
Error message
State token was not created for external OAuth flow
What it means
Raised (HTTP 400) by the external OAuth complete endpoint when the state token itself is valid but has no `callback_url` attached. Only state tokens created by the external authorize endpoint (which stores the external callback URL in the state metadata) are accepted here; states created by the platform's internal OAuth flow have `callback_url=None` and are rejected.
Source
Thrown at autogpt_platform/backend/backend/api/external/v1/integrations.py:426
This endpoint should be called after the user has authorized the application
and been redirected back to the external app's callback URL with an
authorization code.
"""
# Verify state token
valid_state = await creds_manager.store.verify_state_token(
auth.user_id, request.state_token, provider
)
if not valid_state:
logger.warning(f"Invalid or expired state token for provider {provider}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid or expired state token",
)
# Verify this is an external flow (callback_url must be set)
if not valid_state.callback_url:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="State token was not created for external OAuth flow",
)
# Get OAuth handler with the original callback URL
handler = _get_oauth_handler_for_external(provider, valid_state.callback_url)
try:
scopes = valid_state.scopes
scopes = handler.handle_default_scopes(scopes)
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(" ")View on GitHub (pinned to 9c8bb5550f)
Solutions
- Always create state via POST `/integrations/{provider}/oauth/authorize` with a `callback_url` before calling the external callback endpoint.
- Do not reuse state tokens obtained from the platform's internal login/OAuth flow.
- If stale states persist from an older version, restart the flow to generate a new external state.
Example fix
# before
state = start_internal_oauth(provider) # no callback_url
POST /integrations/{provider}/oauth/callback {"state_token": state.token, ...} # 400
# after
resp = POST /integrations/{provider}/oauth/authorize {"callback_url": "https://app.example.com/cb"}
POST /integrations/{provider}/oauth/callback {"state_token": resp.state_token, "code": "..."} Defensive patterns
Strategy: validation
Validate before calling
# Only states created by the EXTERNAL authorize endpoint have a callback_url. # Track provenance client-side: state = authorize_external(provider, callback_url) # marks state as external assert state.origin == "external", "use /oauth/authorize with callback_url, not internal flow"
Try / catch
try:
client.post(f"/integrations/{provider}/oauth/callback", json=cb)
except HTTPError as e:
if e.response.status_code == 400 and "external OAuth flow" in e.response.text:
raise FlowError("state came from internal flow; re-initiate via external authorize") from e
raise Prevention
- Use one code path (external authorize) for external-app integrations; never mix in internal-flow states.
- Tag stored states with their flow type client-side to catch mismatches early.
When it happens
Trigger: POST `/api/external-api/v1/integrations/{provider}/oauth/callback` with a state token that came from the platform's own (internal) OAuth initiation instead of the external `/oauth/authorize` endpoint; or a state stored before the external-flow metadata field existed.
Common situations: Mixing the internal platform OAuth endpoints with the external API endpoints in one integration script; copying state examples from internal-flow docs; stale state rows persisted by an older backend version that lacked `callback_url` in `OAuthState`.
Related errors
- Invalid or expired state token
- 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
- Provider '{provider}' not found
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/e64eebcf40bde7fa.
Report an issue: GitHub.