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
- Verify the client_id used to start the login flow matches the client_id passed to extract_user_info.
- Decode the token payload and inspect `aud`; re-login with the correct OAuth client so the token lists your client_id.
- 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
- Keep client_id consistent between the authorize request and validation call.
- After changing OAuth app registration, force users to re-authenticate.
- Log aud claims when debugging multi-app setups.
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
- OidcError::UnsupportedAlg
- OidcError::AlgNotInDiscoverySupportedList
- OidcError::IdTokenMissingKid
- OidcError::IssuerMismatch
- Server returned invalid user_code format (expected [A-Z0-9-]
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/3bb45ca15e9de468.
Report an issue: GitHub.