xai-org/grok-build · error

Server returned invalid verification URI

Error message

Server returned invalid verification URI

What it means

validate_verification_uri rejects verification URIs that cannot be safely shown/opened: any URI containing ASCII control characters, or a URI that fails url::Url::parse entirely. This protects users from opening malformed or attacker-crafted links supplied by the issuer.

Source

Thrown at crates/codegen/xai-grok-shell/src/auth/device_code.rs:516

    use base64::Engine;
    let parts: Vec<&str> = jwt.splitn(3, '.').collect();
    if parts.len() < 2 {
        return (String::new(), None);
    }
    let payload = match base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(parts[1]) {
        Ok(bytes) => bytes,
        Err(_) => return (String::new(), None),
    };
    let claims: IdTokenClaims = match serde_json::from_slice(&payload) {
        Ok(claims) => claims,
        Err(_) => return (String::new(), None),
    };
    (claims.sub.unwrap_or_default(), claims.email)
}

fn validate_verification_uri(uri: &str) -> anyhow::Result<()> {
    if uri.chars().any(|c| c.is_ascii_control()) {
        anyhow::bail!("Server returned invalid verification URI");
    }

    let parsed = url::Url::parse(uri)
        .map_err(|_| anyhow::anyhow!("Server returned invalid verification URI"))?;

    match parsed.scheme() {
        "https" => Ok(()),
        "http" if matches!(parsed.host_str(), Some("localhost") | Some("127.0.0.1")) => Ok(()),
        _ => anyhow::bail!("Server returned unsupported verification URI scheme"),
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use std::sync::Arc;

    use super::{AuthManager, build_auth, validate_verification_uri};
    use crate::auth::{AuthMode, GrokComConfig};

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Inspect the device-authorization response to see the malformed verification_uri value.
  2. Fix the base URL / issuer configuration so the real xAI OAuth2 endpoint is used.
  3. If using a proxy, correct it to pass through the issuer's absolute https verification URI.
  4. Update the client/server pair so response shapes match.

Example fix

// before: server returns relative or dirty URI
{"verification_uri": "x.ai/device\n"}
// after: clean absolute URL
{"verification_uri": "https://x.ai/device"}
Defensive patterns

Strategy: validation

Validate before calling

fn verification_uri_plausible(uri: &str) -> bool {
    !uri.is_empty()
        && !uri.chars().any(char::is_control)
        && url::Url::parse(uri).is_ok()
}
// run on the response before invoking the login flow

Type guard

fn checked_uri(uri: &str) -> Option<url::Url> {
    if uri.chars().any(char::is_control) { return None; }
    url::Url::parse(uri).ok()
}

Try / catch

match request_device_code(&client, &cfg).await {
    Err(e) if e.to_string().contains("invalid verification URI") => {
        eprintln!("Issuer returned a bad verification URL; check base-URL config/proxy.");
    }
    other => other?,
}

Prevention

When it happens

Trigger: request_device_code calls validate_verification_uri on server_resp.verification_uri (or verification_uri_complete) and the string contains control chars (e.g. \n, \t, \x1b) or is not a parseable absolute URL.

Common situations: A proxy or mock server returns an error body/HTML in the verification_uri field; issuer omits the field so an empty string is validated; environment variable misconfiguration points the client at a non-OAuth2 endpoint.

Related errors


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