{"record":{"id":"6f0bd8f5a8da9fcb","repo":"xai-org/grok-build","slug":"oidcerror-discoverymissingjwksuri","errorCode":null,"errorMessage":"OidcError::DiscoveryMissingJwksUri","messagePattern":"OidcError::DiscoveryMissingJwksUri","errorType":"validation","errorClass":"OidcError","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs","lineNumber":652,"sourceCode":"        ));\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))?;\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,","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs#L634-L670","documentation":"OidcError::DiscoveryMissingJwksUri is raised by validate_and_extract_user_info when the fetched discovery document has no `jwks_uri` field. Without the JWKS URL the shell cannot fetch signing keys, so id_token verification is impossible. This indicates an incomplete or non-compliant discovery document.","triggerScenarios":"validate_and_extract_user_info reads discovery.jwks_uri after discovery succeeded; if the Option is None, DiscoveryMissingJwksUri is returned before any JWKS request is made.","commonSituations":"Minimal or homegrown OIDC providers that omit jwks_uri from their well-known JSON; a reverse proxy stripping fields; caching/interception serving a truncated discovery payload.","solutions":["Fix the provider's discovery document to include jwks_uri (spec-required for signing-key distribution)","curl the well-known URL and confirm the JSON actually contains jwks_uri (rule out proxies/caches stripping it)","Check for issuer-path misconfig causing discovery to be read from a metadata endpoint that lacks jwks_uri"],"exampleFix":"// before (IdP discovery response)\n{ \"issuer\": \"https://idp.example.com\", \"authorization_endpoint\": \"...\" }\n// after\n{ \"issuer\": \"https://idp.example.com\", \"jwks_uri\": \"https://idp.example.com/.well-known/jwks.json\", ... }","handlingStrategy":"validation","validationCode":"// preflight discovery completeness before the login flow\nasync fn discovery_has_jwks(issuer: &str) -> anyhow::Result<bool> {\n    let url = format!(\"{}/.well-known/openid-configuration\", issuer.trim_end_matches('/'));\n    let doc: serde_json::Value = reqwest::get(&url).await?.json().await?;\n    Ok(doc.get(\"jwks_uri\").and_then(|v| v.as_str()).is_some())\n}","typeGuard":null,"tryCatchPattern":"match res {\n    Err(e) if matches!(e.downcast_ref::<OidcError>(), Some(OidcError::DiscoveryMissingJwksUri)) => {\n        eprintln!(\"Issuer discovery has no jwks_uri — provider metadata is incomplete\");\n    }\n    other => other?,\n}","preventionTips":["curl the well-known document on issuer setup and confirm jwks_uri exists","Beware proxies/caches that strip fields from discovery JSON","Validate OIDC provider compliance (issuer, jwks_uri, token_endpoint) before configuring it"],"tags":["oidc","discovery","jwks"],"backgroundTag":"missing-jwks-uri","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}