xai-org/grok-build · error · OidcError

OidcError::IdTokenMissingKid

Error message

OidcError::IdTokenMissingKid

What it means

OidcError::IdTokenMissingKid is raised by validate_and_extract_user_info when the id_token's JOSE header lacks a `kid` (key ID). The library needs `kid` to select the matching JWK from the provider's JWKS for signature verification, so a token without it cannot be validated.

Source

Thrown at crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs:648

        return Err(anyhow::Error::new(
            OidcError::AlgNotInDiscoverySupportedList {
                alg: alg_name.to_owned(),
            },
        ));
    }
    Ok(())
}
pub(super) async fn validate_and_extract_user_info(
    token: &str,
    discovery: &Discovery,
    expected_issuer: &str,
    expected_client_id: &str,
    expected_nonce: &str,
) -> anyhow::Result<OidcUserInfo> {
    let header = jsonwebtoken::decode_header(token)?;
    let kid = header
        .kid
        .ok_or_else(|| anyhow::Error::new(OidcError::IdTokenMissingKid))?;
    let jwks_uri = discovery
        .jwks_uri
        .as_ref()
        .ok_or_else(|| anyhow::Error::new(OidcError::DiscoveryMissingJwksUri))?;
    let jwks: jsonwebtoken::jwk::JwkSet = with_alpha_test_key(
        crate::http::shared_client()
            .get(jwks_uri)
            .timeout(std::time::Duration::from_secs(10)),
        jwks_uri,
    )
    .send()
    .await?
    .error_for_status()?
    .json()
    .await?;
    let jwk = jwks
        .find(&kid)
        .ok_or_else(|| anyhow::Error::new(OidcError::JwkNotFound { kid: kid.clone() }))?;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Configure the IdP to include the kid header in issued id_tokens (standard behavior for multi-key JWKS providers)
  2. If the provider uses a single key, it must still set kid to conform to OIDC spec; file/request a provider fix
  3. Try a different provider/realm that issues spec-compliant tokens
Defensive patterns

Strategy: validation

Validate before calling

// inspect the unverified header first; fail fast with a clearer message
fn header_has_kid(token: &str) -> bool {
    jsonwebtoken::decode_header(token).map(|h| h.kid.is_some()).unwrap_or(false)
}

Try / catch

match res {
    Err(e) if matches!(e.downcast_ref::<OidcError>(), Some(OidcError::IdTokenMissingKid)) => {
        eprintln!("Provider omits kid in id_token header; provider must include kid per OIDC spec");
    }
    other => other?,
}

Prevention

When it happens

Trigger: decode_header(token) succeeds but header.kid is None during id_token validation after the token exchange/refresh.

Common situations: Providers that sign with a single static key and omit `kid` in the JWS header; non-standard or homegrown OIDC servers; proxy-rewritten tokens.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/3ea3571ee8b15785. Report an issue: GitHub.