{"record":{"id":"d9e2a5f58e049141","repo":"xai-org/grok-build","slug":"oidcerror-algnotindiscoverysupportedlist","errorCode":null,"errorMessage":"OidcError::AlgNotInDiscoverySupportedList","messagePattern":"OidcError::AlgNotInDiscoverySupportedList","errorType":"validation","errorClass":"OidcError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs","lineNumber":630,"sourceCode":"            jsonwebtoken::Algorithm::HS512 => \"HS512\",\n            _ => \"unknown\",\n        },\n    }\n}\npub(super) fn ensure_alg_allowed(\n    alg: jsonwebtoken::Algorithm,\n    discovery_supported_algs: Option<&[String]>,\n) -> anyhow::Result<()> {\n    let alg_name = alg_to_jwa_name(alg);\n    if !ALLOWED_ID_TOKEN_ALGS.contains(&alg) {\n        return Err(anyhow::Error::new(OidcError::UnsupportedAlg(\n            alg_name.to_owned(),\n        )));\n    }\n    if let Some(supported) = discovery_supported_algs\n        && !supported.iter().any(|a| a == alg_name)\n    {\n        return Err(anyhow::Error::new(\n            OidcError::AlgNotInDiscoverySupportedList {\n                alg: alg_name.to_owned(),\n            },\n        ));\n    }\n    Ok(())\n}\npub(super) async fn validate_and_extract_user_info(\n    token: &str,\n    discovery: &Discovery,\n    expected_issuer: &str,\n    expected_client_id: &str,\n    expected_nonce: &str,\n) -> anyhow::Result<OidcUserInfo> {\n    let header = jsonwebtoken::decode_header(token)?;\n    let kid = header\n        .kid\n        .ok_or_else(|| anyhow::Error::new(OidcError::IdTokenMissingKid))?;","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs#L612-L648","documentation":"OidcError::AlgNotInDiscoverySupportedList is raised by ensure_alg_allowed when the id_token algorithm passes the hardcoded allow-list but is absent from the provider's discovery document `id_token_signing_alg_values_supported`. The library treats discovery as authoritative about what the provider may issue.","triggerScenarios":"validate_and_extract_user_info -> ensure_alg_allowed is passed discovery_supported_algs; if Some(list) and no entry equals the token's JWA alg name, AlgNotInDiscoverySupportedList { alg } is returned.","commonSituations":"IdP signs with an algorithm not advertised in its own discovery metadata (provider misconfiguration), or discovery metadata is stale/cached after an IdP algorithm rotation.","solutions":["Fix the IdP discovery document to include the algorithm it actually signs with (provider-side config)","Verify the id_token's alg matches one of the algs advertised by the issuer's well-known document","Refresh/re-fetch discovery (restart the flow) if the provider rotated algorithms and metadata is stale"],"exampleFix":"// before (IdP discovery doc)\n\"id_token_signing_alg_values_supported\": [\"RS256\"]  // token signed ES256\n// after\n\"id_token_signing_alg_values_supported\": [\"RS256\", \"ES256\"]","handlingStrategy":"validation","validationCode":"// compare the token's alg against discovery's advertised list before validation\nfn alg_in_discovery(alg_name: &str, discovery_algs: Option<&[String]>) -> bool {\n    match discovery_algs {\n        None => true, // unchecked when discovery omits the field\n        Some(list) => list.iter().any(|a| a == alg_name),\n    }\n}","typeGuard":null,"tryCatchPattern":"match res {\n    Err(e) if matches!(e.downcast_ref::<OidcError>(), Some(OidcError::AlgNotInDiscoverySupportedList { alg })) => {\n        eprintln!(\"IdP signs with {alg} but does not advertise it; fix the provider's discovery metadata\");\n    }\n    other => other?,\n}","preventionTips":["Keep the IdP's id_token_signing_alg_values_supported in sync with its actual signing key","Re-fetch discovery after an IdP algorithm rotation (stale metadata causes this)","Audit provider well-known documents when onboarding a new issuer"],"tags":["oidc","jwt","discovery","algorithm"],"backgroundTag":"jwt-alg-discovery-mismatch","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}