xai-org/grok-build · error · OidcError

AudienceMismatch

AudienceMismatch

Error message

OidcError::AudienceMismatch

What it means

OidcError::AudienceMismatch is thrown when the ID token's `aud` claim does not contain the expected client_id (checked via aud_matches in validate_and_extract_user_info, protocol.rs:686-689). The `aud` claim identifies who the token was issued for; if this client isn't an audience, the token must not be accepted even if the signature is valid.

Source

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

        discovery.id_token_signing_alg_values_supported.as_deref(),
    )?;
    let mut validation = jsonwebtoken::Validation::new(alg);
    validation.set_issuer(&[expected_issuer]);
    validation.set_audience(&[expected_client_id]);
    validation.validate_exp = true;
    validation.validate_aud = true;
    validation.required_spec_claims = ["sub", "iss", "aud", "exp"]
        .into_iter()
        .map(ToOwned::to_owned)
        .collect();
    let token_data = jsonwebtoken::decode::<IdTokenClaims>(token, &decoding_key, &validation)?;
    if token_data.claims.iss.as_deref() != Some(expected_issuer) {
        return Err(anyhow::Error::new(OidcError::IssuerMismatch));
    }
    if let Some(ref aud) = token_data.claims.aud
        && !aud_matches(aud, expected_client_id)
    {
        return Err(anyhow::Error::new(OidcError::AudienceMismatch));
    }
    if token_data.claims.nonce.as_deref() != Some(expected_nonce) {
        return Err(anyhow::Error::new(OidcError::NonceMismatch));
    }
    Ok(OidcUserInfo {
        user_id: token_data
            .claims
            .sub
            .unwrap_or_else(|| "unknown".to_string()),
        email: token_data.claims.email,
        first_name: token_data.claims.first_name,
        last_name: token_data.claims.last_name,
        profile_image_asset_id: token_data.claims.picture,
        principal_type: None,
        principal_id: None,
        team_id: None,
        team_name: None,
        team_role: None,

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Verify the client_id used to start the login flow matches the client_id passed to extract_user_info.
  2. Decode the token payload and inspect `aud`; re-login with the correct OAuth client so the token lists your client_id.
  3. Update the client configuration to the client_id the IdP actually issues tokens for.

Example fix

// before: mismatched client id
let client_id = "grok-shell-old";
let user = extract_user_info(Some(&token), &discovery, &issuer, client_id, &nonce, ...).await?;
// after: client id registered with the IdP for this app
let client_id = "grok-shell";
Defensive patterns

Strategy: validation

Validate before calling

// pre-check aud claim
fn token_aud(token: &str) -> Option<serde_json::Value> {
    let payload = token.split('.').nth(1)?;
    let bytes = base64_url::decode(payload).ok()?;
    serde_json::from_slice::<serde_json::Value>(&bytes).ok()?.remove("aud")
}
if let Some(aud) = token_aud(token) { /* verify expected_client_id appears in aud (string or array) */ }

Type guard

fn aud_contains(token: &str, client_id: &str) -> bool {
    match token_aud(token) {
        Some(serde_json::Value::String(s)) => s == client_id,
        Some(serde_json::Value::Array(a)) => a.iter().any(|v| v.as_str() == Some(client_id)),
        _ => true, // absent aud is not rejected by the library
    }
}

Try / catch

match result {
    Err(e) if e.to_string().contains("AudienceMismatch") => eprintln!("token aud does not include client_id; re-login with correct client"),
    other => other,
}

Prevention

When it happens

Trigger: extract_user_info called with expected_client_id C while the token's `aud` is a different client id (or an array not containing C). Note: when `aud` is absent the check is skipped; the error fires only on a present-but-mismatched aud.

Common situations: Client ID changed in config after the token was minted; using a token issued to another OAuth application; copy-pasted client_secret/client_id from a sibling app; multi-audience tokens where the expected client was dropped.

Related errors


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