{"record":{"id":"180e7a2a6427a9a2","repo":"xai-org/grok-build","slug":"oidcerror-statemismatch","errorCode":null,"errorMessage":"OidcError::StateMismatch","messagePattern":"OidcError::StateMismatch","errorType":"exception","errorClass":"OidcError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs","lineNumber":593,"sourceCode":"    pub(super) first_name: Option<String>,\n    #[serde(default, alias = \"family_name\")]\n    pub(super) last_name: Option<String>,\n    #[serde(default)]\n    pub(super) picture: Option<String>,\n}\npub(super) fn aud_matches(aud: &serde_json::Value, expected: &str) -> bool {\n    match aud {\n        serde_json::Value::String(s) => s == expected,\n        serde_json::Value::Array(values) => values\n            .iter()\n            .any(|v| matches!(v, serde_json::Value::String(s) if s == expected)),\n        _ => false,\n    }\n}\npub(super) fn validate_state(expected: &str, received: &str) -> anyhow::Result<()> {\n    if received != expected {\n        tracing::warn!(expected = %expected, received = %received, \"OIDC: state mismatch\");\n        return Err(anyhow::Error::new(OidcError::StateMismatch));\n    }\n    Ok(())\n}\n/// Explicit JWA name mapping — avoids coupling to `jsonwebtoken::Algorithm`'s `Debug` repr.\npub(super) fn alg_to_jwa_name(alg: jsonwebtoken::Algorithm) -> &'static str {\n    match alg {\n        jsonwebtoken::Algorithm::RS256 => \"RS256\",\n        jsonwebtoken::Algorithm::RS384 => \"RS384\",\n        jsonwebtoken::Algorithm::RS512 => \"RS512\",\n        jsonwebtoken::Algorithm::PS256 => \"PS256\",\n        jsonwebtoken::Algorithm::PS384 => \"PS384\",\n        jsonwebtoken::Algorithm::PS512 => \"PS512\",\n        jsonwebtoken::Algorithm::ES256 => \"ES256\",\n        jsonwebtoken::Algorithm::ES384 => \"ES384\",\n        jsonwebtoken::Algorithm::EdDSA => \"EdDSA\",\n        other => match other {\n            jsonwebtoken::Algorithm::HS256 => \"HS256\",\n            jsonwebtoken::Algorithm::HS384 => \"HS384\",","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs#L575-L611","documentation":"OidcError::StateMismatch is raised by validate_state when the `state` parameter received on the OIDC callback does not equal the state value generated at login start. State is a CSRF protection; a mismatch means the callback response cannot be trusted to belong to this login session.","triggerScenarios":"run_login_flow_with_config receives a callback and calls validate_state(expected, received); any string inequality triggers StateMismatch.","commonSituations":"Multiple concurrent login sessions whose callbacks crossed, browser/race delivering a stale callback, replayed or forged redirect, truncation of the state in a URL-length-limited relay.","solutions":["Restart the login flow cleanly and use only the most recent login session's URL","Ensure no other login is running in parallel that could mix callbacks","Do not reuse or hand-edit the authorize URL; let the flow generate a fresh state"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// client-side sanity: ensure the callback state matches what the flow generated\nfn states_match(expected: &str, received: &str) -> bool {\n    !expected.is_empty() && constant_time_eq(expected.as_bytes(), received.as_bytes())\n}","typeGuard":null,"tryCatchPattern":"match res {\n    Err(e) if matches!(e.downcast_ref::<OidcError>(), Some(OidcError::StateMismatch)) => {\n        eprintln!(\"CSRF state mismatch — restart the login and use the newest URL\");\n    }\n    other => other?,\n}","preventionTips":["Run only one login session at a time so callbacks cannot cross","Always use the freshly printed authorize URL; never reuse an old one","Don't relay the callback through services that truncate query parameters"],"tags":["oidc","csrf","state-validation"],"backgroundTag":"oauth-state-mismatch","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}