{"record":{"id":"1e6eb447bca52925","repo":"xai-org/grok-build","slug":"server-returned-invalid-verification-uri","errorCode":null,"errorMessage":"Server returned invalid verification URI","messagePattern":"Server returned invalid verification URI","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/device_code.rs","lineNumber":516,"sourceCode":"    use base64::Engine;\n    let parts: Vec<&str> = jwt.splitn(3, '.').collect();\n    if parts.len() < 2 {\n        return (String::new(), None);\n    }\n    let payload = match base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(parts[1]) {\n        Ok(bytes) => bytes,\n        Err(_) => return (String::new(), None),\n    };\n    let claims: IdTokenClaims = match serde_json::from_slice(&payload) {\n        Ok(claims) => claims,\n        Err(_) => return (String::new(), None),\n    };\n    (claims.sub.unwrap_or_default(), claims.email)\n}\n\nfn validate_verification_uri(uri: &str) -> anyhow::Result<()> {\n    if uri.chars().any(|c| c.is_ascii_control()) {\n        anyhow::bail!(\"Server returned invalid verification URI\");\n    }\n\n    let parsed = url::Url::parse(uri)\n        .map_err(|_| anyhow::anyhow!(\"Server returned invalid verification URI\"))?;\n\n    match parsed.scheme() {\n        \"https\" => Ok(()),\n        \"http\" if matches!(parsed.host_str(), Some(\"localhost\") | Some(\"127.0.0.1\")) => Ok(()),\n        _ => anyhow::bail!(\"Server returned unsupported verification URI scheme\"),\n    }\n}\n\n#[cfg(test)]\npub(crate) mod tests {\n    use std::sync::Arc;\n\n    use super::{AuthManager, build_auth, validate_verification_uri};\n    use crate::auth::{AuthMode, GrokComConfig};","sourceCodeStart":498,"sourceCodeEnd":534,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/device_code.rs#L498-L534","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the device-authorization response to see the malformed verification_uri value.","Fix the base URL / issuer configuration so the real xAI OAuth2 endpoint is used.","If using a proxy, correct it to pass through the issuer's absolute https verification URI.","Update the client/server pair so response shapes match."],"exampleFix":"// before: server returns relative or dirty URI\n{\"verification_uri\": \"x.ai/device\\n\"}\n// after: clean absolute URL\n{\"verification_uri\": \"https://x.ai/device\"}","handlingStrategy":"validation","validationCode":"fn verification_uri_plausible(uri: &str) -> bool {\n    !uri.is_empty()\n        && !uri.chars().any(char::is_control)\n        && url::Url::parse(uri).is_ok()\n}\n// run on the response before invoking the login flow","typeGuard":"fn checked_uri(uri: &str) -> Option<url::Url> {\n    if uri.chars().any(char::is_control) { return None; }\n    url::Url::parse(uri).ok()\n}","tryCatchPattern":"match request_device_code(&client, &cfg).await {\n    Err(e) if e.to_string().contains(\"invalid verification URI\") => {\n        eprintln!(\"Issuer returned a bad verification URL; check base-URL config/proxy.\");\n    }\n    other => other?,\n}","preventionTips":["Point the client at the official issuer; avoid rewriting OAuth2 responses in proxies.","Reject/mock servers that omit verification_uri rather than validating empty strings.","Test the device endpoint's response shape after any issuer upgrade.","Log raw responses when validation fails to spot HTML/error bodies."],"tags":["oauth","device-flow","url-validation"],"backgroundTag":"invalid-server-response-format","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}