xai-org/grok-build · error · OidcError
MissingIdToken
MissingIdToken
Error message
OidcError::MissingIdToken
What it means
OidcError::MissingIdToken is thrown by extract_user_info when no `principal_type == team` shortcut applies and the optional id_token parameter is None (protocol.rs:747). Without an ID token there is nothing to validate or extract user claims from, so the login flow cannot proceed.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/oidc/protocol.rs:747
user_id: team_user_id,
email: None,
first_name: None,
last_name: None,
profile_image_asset_id: None,
principal_type: Some(crate::auth::model::TEAM_PRINCIPAL_TYPE.to_string()),
principal_id: principal_id.map(ToOwned::to_owned),
team_id: principal_id.map(ToOwned::to_owned).or(fallback_team_id),
team_name: None,
team_role: None,
organization_id: None,
organization_name: None,
organization_role: None,
user_blocked_reason: None,
team_blocked_reasons: vec![],
coding_data_retention_opt_out: crate::auth::default_coding_data_retention_opt_out(),
});
}
let token = id_token.ok_or_else(|| anyhow::Error::new(OidcError::MissingIdToken))?;
validate_and_extract_user_info(
token,
discovery,
expected_issuer,
expected_client_id,
expected_nonce,
)
.await
.map(|mut user_info| {
user_info.principal_type = principal_type.map(ToOwned::to_owned);
user_info.principal_id = principal_id.map(ToOwned::to_owned);
if user_info.team_id.is_none() {
user_info.team_id = fallback_team_id;
}
user_info
})
.map_err(|e| anyhow::Error::new(OidcError::IdTokenValidationFailed(e.to_string())))
}View on GitHub (pinned to bc7f02eddd)
Solutions
- Ensure the `openid` scope is included in the authorization request so the provider issues an id_token.
- Log the token endpoint response and confirm an id_token field is present; fix scope/flow parameters if not.
- Use the team-principal path (principal_type=team) only when intentionally skipping ID token validation; otherwise supply the token.
Example fix
// before: request without openid scope
let auth_url = format!("{auth}?client_id={id}&redirect_uri={uri}&response_type=code");
// after: request openid scope so an id_token is returned
let auth_url = format!("{auth}?client_id={id}&redirect_uri={uri}&response_type=code&scope=openid%20profile%20email"); Defensive patterns
Strategy: validation
Validate before calling
// verify the token response carries an id_token before calling extract_user_info
let id_token = token_response.get("id_token").and_then(|v| v.as_str());
if id_token.is_none() {
eprintln!("provider returned no id_token; ensure 'openid' scope requested");
} Type guard
fn has_id_token(resp: &serde_json::Value) -> bool { resp.get("id_token").map_or(false, |v| v.as_str().map_or(false, |s| !s.is_empty())) } Try / catch
match result {
Err(e) if e.to_string().contains("MissingIdToken") => eprintln!("no id_token in response; check scopes/flow"),
other => other,
} Prevention
- Always request the `openid` scope in the authorization request.
- Assert id_token presence in token-endpoint responses during integration tests.
- Use the team-principal path only deliberately.
When it happens
Trigger: The token endpoint response (or device/callback flow result) contained no id_token, and extract_user_info was called with id_token=None for a non-team principal.
Common situations: The IdP is configured to not return id_token for the requested flow/scopes; the token response JSON was parsed with a wrong field name; `openid` scope missing from the authorization request so no id_token is issued; partial response from a race fallback path (full_login_flow_via_race).
Related errors
- IdTokenValidationFailed
- no OIDC auth entry found in {}. Run `grok login` first.
- auth entry has no refresh_token — cannot refresh expired tok
- auth entry has no oidc_issuer — cannot refresh expired token
- auth entry has no oidc_client_id — cannot refresh expired to
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/4ab7103f558cb83e.
Report an issue: GitHub.