{"record":{"id":"2871ed02884e0f1c","repo":"Hmbown/CodeWhale","slug":"codewhale-owned-xai-oauth-credentials-are-inactive-until-the","errorCode":null,"errorMessage":"Codewhale-owned xAI OAuth credentials are inactive until the xAI route explicitly selects OAuth","messagePattern":"Codewhale-owned xAI OAuth credentials are inactive until the xAI route explicitly selects OAuth","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/oauth.rs","lineNumber":2115,"sourceCode":"            \"xAI OAuth credentials at {} have no usable entry. Run `grok login` again or use `codewhale auth xai-device` for Codewhale-owned storage.\",\n            codewhale_config::quote_os_path(grant.path())\n        )\n    })?;\n    if !entry_access_token_is_fresh(&entry) {\n        bail!(\n            \"xAI OAuth access token in {} is expired. Read-only consent never refreshes or rewrites another CLI's credentials. Run `grok login` again or use `codewhale auth xai-device`.\",\n            codewhale_config::quote_os_path(grant.path())\n        );\n    }\n    Ok(())\n}\n\n/// Load xAI OAuth credentials with full precedence: configured generation,\n/// legacy owned file, then the consented Grok CLI import. Codewhale-owned\n/// credentials may refresh and rewrite Codewhale-owned storage; external\n/// credentials are read-only.\npub fn get_xai_credentials(config: &Config) -> Result<OwnedOAuthCredentials> {\n    anyhow::ensure!(\n        config.api_provider() == crate::config::ApiProvider::Xai\n            && config\n                .provider_config_for(crate::config::ApiProvider::Xai)\n                .and_then(|entry| entry.auth_mode.as_deref())\n                .is_some_and(auth_mode_uses_xai_oauth),\n        \"Codewhale-owned xAI OAuth credentials are inactive until the xAI route explicitly selects OAuth\"\n    );\n    if let Some(owned_path) = configured_owned_auth_file_path(OAuthProvider::Xai, config)? {\n        return get_owned_credentials_at(OAuthProvider::Xai, &owned_path);\n    }\n    let owned_path = codewhale_config::legacy_xai_oauth_path()?;\n    if load_owned_auth_file(&owned_path)?.is_some() {\n        return get_owned_credentials_at(OAuthProvider::Xai, &owned_path);\n    }\n\n    let external_path = grok_auth_file_path();\n    let grant = config.external_credential_read_grant(\n        crate::config::ApiProvider::Xai,","sourceCodeStart":2097,"sourceCodeEnd":2133,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/oauth.rs#L2097-L2133","documentation":"get_xai_credentials refuses to load Codewhale-owned xAI OAuth credentials unless the active API provider is Xai AND that provider's config explicitly selects an xAI-OAuth auth_mode (checked with auth_mode_uses_xai_oauth). This prevents silently using stored OAuth tokens when the route is configured for API-key auth or a different provider.","triggerScenarios":"Calling get_xai_credentials when config.api_provider() != ApiProvider::Xai, or when provider_config_for(Xai).auth_mode is absent or not an xAI-OAuth mode (e.g. \"api_key\" or unset).","commonSituations":"User completed `codewhale auth xai-device` but the xAI route in config still specifies api_key auth_mode; config file edited to remove auth_mode; credentials carried over from an experiment while the route points elsewhere.","solutions":["Set the xAI provider entry's auth_mode to the OAuth mode in your Codewhale config (or re-run `codewhale auth xai-device`, which configures it).","If you intend API-key auth, stop relying on OAuth credentials and supply an API key instead.","Check that the active route actually selects ApiProvider::Xai."],"exampleFix":"// before (config)\n[xai]\nauth_mode = \"api_key\"\n// after\n[xai]\nauth_mode = \"oauth\"  # the xAI-OAuth auth mode accepted by auth_mode_uses_xai_oauth","handlingStrategy":"validation","validationCode":"if (cfg.api_provider !== 'xai' || !/^oauth/.test(cfg.providers?.xai?.auth_mode ?? '')) fixAuthMode(cfg);","typeGuard":"const xaiOauthActive = (cfg) => cfg.api_provider === 'xai' && typeof cfg.providers?.xai?.auth_mode === 'string' && cfg.providers.xai.auth_mode.includes('oauth');","tryCatchPattern":"try { getXaiCredentials(); } catch (e) { if (String(e).includes('inactive until the xAI route')) updateConfigAuthMode('oauth'); }","preventionTips":["Keep auth_mode and the active provider route in sync in config","Re-run `codewhale auth xai-device` after config changes so it rewrites auth_mode","Audit config for auth_mode = \"api_key\" before relying on OAuth credentials"],"tags":["oauth","config","xai"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}