{"record":{"id":"1e7567736ec35add","repo":"xai-org/grok-build","slug":"oidcerror-jwknotfound","errorCode":null,"errorMessage":"OidcError::JwkNotFound","messagePattern":"OidcError::JwkNotFound","errorType":"validation","errorClass":"OidcError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs","lineNumber":666,"sourceCode":"        .ok_or_else(|| anyhow::Error::new(OidcError::IdTokenMissingKid))?;\n    let jwks_uri = discovery\n        .jwks_uri\n        .as_ref()\n        .ok_or_else(|| anyhow::Error::new(OidcError::DiscoveryMissingJwksUri))?;\n    let jwks: jsonwebtoken::jwk::JwkSet = with_alpha_test_key(\n        crate::http::shared_client()\n            .get(jwks_uri)\n            .timeout(std::time::Duration::from_secs(10)),\n        jwks_uri,\n    )\n    .send()\n    .await?\n    .error_for_status()?\n    .json()\n    .await?;\n    let jwk = jwks\n        .find(&kid)\n        .ok_or_else(|| anyhow::Error::new(OidcError::JwkNotFound { kid: kid.clone() }))?;\n    let decoding_key = jsonwebtoken::DecodingKey::from_jwk(jwk)?;\n    let alg = header.alg;\n    ensure_alg_allowed(\n        alg,\n        discovery.id_token_signing_alg_values_supported.as_deref(),\n    )?;\n    let mut validation = jsonwebtoken::Validation::new(alg);\n    validation.set_issuer(&[expected_issuer]);\n    validation.set_audience(&[expected_client_id]);\n    validation.validate_exp = true;\n    validation.validate_aud = true;\n    validation.required_spec_claims = [\"sub\", \"iss\", \"aud\", \"exp\"]\n        .into_iter()\n        .map(ToOwned::to_owned)\n        .collect();\n    let token_data = jsonwebtoken::decode::<IdTokenClaims>(token, &decoding_key, &validation)?;\n    if token_data.claims.iss.as_deref() != Some(expected_issuer) {\n        return Err(anyhow::Error::new(OidcError::IssuerMismatch));","sourceCodeStart":648,"sourceCodeEnd":684,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs#L648-L684","documentation":"OidcError::JwkNotFound is thrown in validate_and_extract_user_info when the `kid` header of the received ID token does not match any key in the JSON Web Key Set (JWKS) fetched from the provider's `jwks_uri`. The library cannot obtain the public key needed to verify the token's signature, so it refuses to trust the token. This guards against forged or from-an-unknown-IdP tokens.","triggerScenarios":"Calling extract_user_info/validate_and_extract_user_info with an ID token whose `kid` is absent from the JWKS currently published at discovery.jwks_uri (lines 664-666 of protocol.rs).","commonSituations":"The identity provider rotated signing keys and the old key was removed before the cached token was validated; the token was issued by a different environment/tenant (staging token against prod discovery); a misconfigured issuer URL points the client at the wrong provider's JWKS; token tampering.","solutions":["Re-run the OIDC login flow to obtain a freshly signed ID token from the current provider keys.","Verify discovery (issuer/jwks_uri) points at the same environment that issued the token.","Check the provider's JWKS endpoint manually and confirm the token's `kid` is present (curl the jwks_uri).","If the IdP recently rotated keys, wait for key publication/propagation and retry."],"exampleFix":"// before: validating a token signed by another environment\nlet discovery = fetch_discovery(\"https://auth.example.com\").await?;\nlet user = extract_user_info(Some(&staging_token), &discovery, ...).await?;\n// after: use a token from the same environment, or refresh via login\nlet discovery = fetch_discovery(\"https://staging.auth.example.com\").await?;\nlet user = extract_user_info(Some(&staging_token), &discovery, ...).await?;","handlingStrategy":"retry","validationCode":"// before calling: check the token kid exists in the JWKS\nlet header = jsonwebtoken::decode_header(token)?;\nlet jwks: JwkSet = reqwest::get(&jwks_uri).await?.json().await?;\nif let Some(kid) = header.kid {\n    if jwks.find(&kid).is_none() { eprintln!(\"kid {kid} not in JWKS; refresh token/login\"); }\n}","typeGuard":"fn jwk_available(jwks: &JwkSet, kid: &str) -> bool { jwks.find(kid).is_some() }","tryCatchPattern":"match extract_user_info(...).await {\n    Err(e) if e.to_string().contains(\"JwkNotFound\") => retry_login_with_fresh_token(),\n    other => other,\n}","preventionTips":["Always obtain tokens via a fresh login against the same environment as the discovery document.","Cache JWKS with a TTL and refetch on unknown kid.","Monitor IdP key-rotation announcements.","Verify issuer/jwks_uri configuration per environment."],"tags":["oidc","jwks","jwt-signature","auth"],"backgroundTag":"jwt-signing-key-not-found","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}