bytedance/deer-flow · warning · HTTPException
Missing code or state parameter
Error message
Missing code or state parameter
What it means
400 Bad Request from the SSO callback handler (auth.py:767) when the IdP's redirect back to /api/auth/sso/{provider}/callback lacks either the 'code' or the 'state' query parameter. In a healthy authorization-code flow the IdP always returns both; their absence means the callback URL was hand-built, mangled by a proxy, or the IdP is misbehaving (an IdP-side failure normally comes back as 'error'/'error_description' params, which are handled earlier with a 302 to 'sso_failed').
Source
Thrown at backend/app/gateway/routers/auth.py:767
# ── Provider error ───────────────────────────────────────────────
if error:
logger.warning("OIDC provider returned error for %s: %s (description: %s)", provider, error, error_description)
redirect = _build_error_redirect(oidc_config.frontend_base_url, "sso_failed")
return RedirectResponse(url=redirect, status_code=status.HTTP_302_FOUND)
if not oidc_config.enabled:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="SSO authentication is not enabled")
if not _OIDC_PROVIDER_KEY_RE.match(provider):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid provider ID")
provider_config = oidc_config.providers.get(provider)
if not provider_config:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unknown SSO provider: {provider}")
if not code or not state:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Missing code or state parameter")
# ── Verify state cookie ──────────────────────────────────────────
state_payload = get_state_cookie(request, provider)
if not state_payload:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Missing or expired OIDC state cookie")
if not secrets.compare_digest(state_payload.state, state):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="OIDC state mismatch")
# ── Resolve redirect URI ─────────────────────────────────────────
redirect_uri = _resolve_oidc_redirect_uri(request, provider, provider_config)
# ── Get metadata ─────────────────────────────────────────────────
overrides = {
"authorization_endpoint": provider_config.authorization_endpoint,
"token_endpoint": provider_config.token_endpoint,
"userinfo_endpoint": provider_config.userinfo_endpoint,
"jwks_uri": provider_config.jwks_uri,View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-run the login flow from the start route and capture the exact redirect Location the IdP emits — confirm it carries both code and state
- Fix any proxy/rewrite rule that drops query strings on the callback path (avoid proxy_pass with a path component that discards the original URI query)
- Verify the IdP app's redirect URI matches the Gateway callback route exactly so the IdP appends parameters correctly
Example fix
# nginx (before) — path-style proxy_pass drops query handling subtleties
location /api/auth/sso/ {
proxy_pass http://gateway:8001/api/auth/sso; # trailing-slash mismatch
}
# after — clean pass-through preserving the full URI + query
location /api/auth/sso/ {
proxy_pass http://gateway:8001;
} Defensive patterns
Strategy: validation
Validate before calling
# Validate the IdP redirect Location before following it
loc = idp_response.headers["location"]
from urllib.parse import urlparse, parse_qs
q = parse_qs(urlparse(loc).query)
assert "code" in q and "state" in q, f"callback missing params: {loc}" Try / catch
try { await callback() } catch (e) { if (e.status === 400 && /Missing code or state/.test(e.detail)) restartSsoFlow(); else throw e; } Prevention
- Never bookmark or directly construct the callback URL; always enter via the start route
- Test the full redirect chain in staging to catch query-string-dropping proxies
- Check the 'error' query param first in your own handlers — IdP failures arrive that way, not as missing code/state
When it happens
Trigger: Direct navigation/bookmark of the callback URL with no query string; a reverse proxy or frontend router stripping query parameters during the redirect; a misconfigured IdP redirect URI template that drops ?code=...&state=...
Common situations: Nginx/proxy rewrite losing the query string (proxy_pass without URI vs with URI pitfalls); testing the callback by pasting the bare URL into a browser; WAF scrubbing query params.
Related errors
- Invalid provider ID
- Unknown SSO provider: {provider}
- Your email could not be verified by the identity provider. P
- The identity provider did not provide an email address.
- Your email domain is not allowed. Please use an approved ema
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/92b157d286ce895f.
Report an issue: GitHub.