Kuberwastaken/claurst · error · anyhow::Error
OAuth callback did not contain an authorization code
Error message
OAuth callback did not contain an authorization code
What it means
The OAuth callback request arrived and matched the expected path, but its query string contained no `code` parameter. This means the authorization server redirected back without granting a code — typically the user denied consent or the server reported an error (e.g. `error=access_denied`) in the query string instead.
Solutions
- Retry the authentication flow and approve the consent prompt in the browser
- Check the callback URL query string for an `error` parameter from the authorization server
- Verify the MCP server's OAuth client is correctly registered with the authorization server
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src-rust/crates/mcp/src/oauth.rs:299 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/99d97b231447bf55.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/oauth.rs:299
parsed_url.path()
);
}
if let Some(expected_state) = expected_state {
let received_state = parsed_url
.query_pairs()
.find(|(key, _)| key == "state")
.map(|(_, value)| value.to_string());
if received_state.as_deref() != Some(expected_state) {
anyhow::bail!("OAuth state mismatch — possible CSRF attack");
}
}
parsed_url
.query_pairs()
.find(|(key, _)| key == "code")
.map(|(_, value)| value.to_string())
.ok_or_else(|| anyhow::anyhow!("OAuth callback did not contain an authorization code"))
}
pub async fn run_mcp_auth_session(session: McpAuthSession) -> anyhow::Result<McpAuthResult> {
let (listener, host, callback_path) = bind_callback_listener(&session.redirect_uri).await?;
open::that(&session.auth_url)
.map_err(|e| anyhow::anyhow!("Failed to open browser for OAuth: {}", e))?;
let code = wait_for_authorization_code(listener, &host, &callback_path, None).await?;
let mut token = exchange_code(
&session.metadata.token_endpoint,
&code,
&session.verifier,
&session.redirect_uri,
)
.await?;
token.server_name = session.server_name.clone();
store_mcp_token(&token).map_err(|e| {
anyhow::anyhow!(View on GitHub (pinned to b0637c97ec)