xai-org/grok-build · error · OidcError
OidcError::CallbackAuthFailed
Error message
OidcError::CallbackAuthFailed
What it means
After a code was received in `race_callback_and_client_ui`, the flow performs the token exchange and any post-callback processing. If that inner `result` is Err, it is wrapped as OidcError::CallbackAuthFailed, preserving the underlying cause. This is not a transport failure — the callback arrived but turning it into tokens failed.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/oidc/login.rs:297
};
drop(tx);
let result = tokio::select! {
r = tokio::time::timeout(AUTH_CALLBACK_TIMEOUT, rx.recv()) => {
r.map_err(|_| anyhow::Error::new(OidcError::CallbackTimeout))?
.ok_or_else(|| anyhow::Error::new(OidcError::CallbackChannelClosed))?
}
_ = client_bridge => {
rx.recv().await
.ok_or_else(|| anyhow::Error::new(OidcError::CallbackChannelClosed))?
}
};
let _ = shutdown_tx.send(());
let _ = server.await;
result.map_err(|e| anyhow::Error::new(OidcError::CallbackAuthFailed(e)))
}
/// Race loopback callback against stdin paste.
async fn race_callback_and_stdin(
listener: TcpListener,
enable_stdin: bool,
) -> anyhow::Result<Callback> {
tracing::debug!(
enable_stdin = enable_stdin,
"OIDC: waiting for auth code (loopback + stdin)"
);
let (tx, mut rx) = tokio::sync::mpsc::channel::<CallbackResult>(1);
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>();
let app = build_callback_router(tx.clone());
let server = tokio::spawn(async move {
let _ = axum::serve(listener, app)
.with_graceful_shutdown(async {View on GitHub (pinned to bc7f02eddd)
Solutions
- Retry the login from scratch — authorization codes are single-use; a reused code yields invalid_grant.
- Verify client_id, client_secret, and redirect_uri exactly match the IDP application registration.
- Check PKCE: code_verifier must be the one bound to the authorize URL; don't re-run only the token step.
- Inspect the wrapped inner error (`e`) for the IDP's OAuth error description (e.g. invalid_grant, unauthorized_client).
- Ensure system clock is accurate (NTP) — large skew breaks token validation.
Example fix
// before: reusing a stale code fails let tokens = exchange(code_from_previous_run)?; // after: redo the full flow to obtain a fresh code let (auth, _created) = run_login_flow(config, auth_manager, channels).await?;
Defensive patterns
Strategy: retry
Validate before calling
// preflight: verify OIDC config before starting the flow
let oidc = config.oidc.as_ref().ok_or("oidc not configured")?;
assert!(!oidc.client_id.is_empty(), "client_id must be set");
reqwest::get(format!("{}/.well-known/openid-configuration", oidc.issuer)).await?; Type guard
fn is_callback_auth_failed(err: &anyhow::Error) -> Option<&anyhow::Error> {
err.downcast_ref::<OidcError>()
.and_then(|e| match e {
OidcError::CallbackAuthFailed(inner) => Some(inner),
_ => None,
})
} Try / catch
match run_login_flow(config, auth_manager, channels).await {
Ok(res) => res,
Err(e) if is_callback_auth_failed(&e).is_some() => {
// codes are single-use: restart the whole flow for a fresh code
run_login_flow(config, auth_manager, channels).await
}
Err(e) => Err(e),
} Prevention
- Never reuse authorization codes — always run the full flow
- Double-check client_id/client_secret/redirect_uri against the IDP registration
- Keep PKCE verifier tied to the same authorize request
- Sync system clock (NTP) to avoid token validation skew
When it happens
Trigger: result.map_err(|e| OidcError::CallbackAuthFailed(e)) at the end of race_callback_and_client_ui — the awaited token exchange / authorization-code processing returned an error.
Common situations: Authorization code already redeemed or expired; PKCE code_verifier mismatch; wrong client_id/client_secret; IDP returned an OAuth error (invalid_grant); clock skew invalidating tokens; IDP temporarily down.
Related errors
- OidcError::TokenExchangeHttp
- Token exchange error: {detail}
- 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
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/44e2e892bf98655d.
Report an issue: GitHub.