{"record":{"id":"4f3a5abc71864834","repo":"Hmbown/CodeWhale","slug":"oauth-bearer-credentials-are-not-an-api-key","errorCode":null,"errorMessage":"OAuth bearer credentials are not an API key","messagePattern":"OAuth bearer credentials are not an API key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/credential_handoff.rs","lineNumber":44,"sourceCode":"    secrets: &Secrets,\n    provider: ProviderKind,\n    runtime_overrides: &CliRuntimeOverrides,\n) -> Result<String> {\n    let resolved = store.config.resolve_runtime_options_with_secrets(\n        &runtime_overrides_for_provider(runtime_overrides, provider),\n        secrets,\n    );\n    if resolved.provider != provider {\n        bail!(\"resolved a different provider\");\n    }\n    let source = resolved.api_key_source;\n    if source != Some(RuntimeApiKeySource::Cli) {\n        if provider == ProviderKind::OpenaiCodex {\n            bail!(\"bearer credentials are not an API key\");\n        }\n        let uses_api_key = provider != ProviderKind::Xai\n            || xai_auth_diagnostics(store, runtime_overrides).evaluates_runtime_api_key();\n        ensure!(uses_api_key, \"OAuth bearer credentials are not an API key\");\n        let kimi_bearer = provider == ProviderKind::Moonshot\n            && resolved\n                .auth_mode\n                .as_deref()\n                .is_some_and(auth_mode_uses_kimi_imported_token);\n        ensure!(!kimi_bearer, \"bearer credentials are not an API key\");\n    }\n    ensure!(source.is_some(), \"no runtime-effective API key\");\n    resolved\n        .api_key\n        .filter(|value| !value.trim().is_empty())\n        .context(\"no usable runtime-effective API key\")\n}\n\npub(crate) fn handoff_secret_line(\n    writer: &mut impl Write,\n    stdout_is_terminal: bool,\n    resolve: impl FnOnce() -> Result<String>,","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/credential_handoff.rs#L26-L62","documentation":"resolve_api_key ensures the resolved credential for the provider is an actual API key, not an OAuth bearer token. For non-Cli sources it checks whether the provider authenticates via API keys (xai is exempt from the check) and rejects the handoff when the effective auth mode is OAuth bearer, since bearer tokens cannot be handed off as API keys.","triggerScenarios":"Requesting an API key handoff for a provider whose runtime credential came from OAuth login (e.g. OpenAI Codex bearer, or Moonshot with an imported Kimi token), so the store resolves a bearer credential rather than an API key.","commonSituations":"User authenticated a provider via OAuth flow but then runs the API-key handoff command; a shared secret store holds a bearer token in the provider's slot; xai/non-key providers configured as the runtime provider while an API key is requested.","solutions":["Log in to the provider with an API key (set the key via the normal key-entry path) so the runtime slot holds an actual API key.","Select a different provider whose runtime credential is an API key, or override with a CLI-provided key (RuntimeApiKeySource::Cli bypasses this check).","For Moonshot, re-authenticate without the imported Kimi token (auth_mode must not be the kimi imported-token mode).","If you need the bearer token itself, use an auth-mode-aware handoff instead of the API-key handoff."],"exampleFix":"// before\n$ codewhale handoff api-key --provider moonshot  # auth_mode = imported kimi token -> refused\n// after\n$ codewhale auth login --provider moonshot --api-key\n$ codewhale handoff api-key --provider moonshot","handlingStrategy":"validation","validationCode":"// before requesting an API-key handoff, confirm the provider's auth mode is key-based\nlet resolved = resolve_provider(provider)?;\nif resolved.auth_mode.is_some() {\n    eprintln!(\"provider uses OAuth bearer auth; API-key handoff unavailable\");\n}","typeGuard":"fn is_api_key_provider(provider: ProviderKind, store: &SecretStore) -> bool {\n    match provider {\n        ProviderKind::OpenaiCodex | ProviderKind::Xai => false,\n        _ => store.api_key_for(provider).map(|k| !k.trim().is_empty()).unwrap_or(false),\n    }\n}","tryCatchPattern":"match resolve_api_key(provider, store, overrides) {\n    Err(e) if e.to_string().contains(\"are not an API key\") => {\n        eprintln!(\"{provider} is authenticated via OAuth; log in with an API key or hand off the bearer token instead\");\n    }\n    Err(e) => return Err(e),\n    Ok(k) => Ok(k),\n}","preventionTips":["Track which providers are OAuth-based per account and skip key-handoff for them.","Authenticate with an API key when you intend to use key-based tooling.","Use CLI-provided key overrides when you must force a key path.","Check auth_mode before choosing between key handoff and token handoff."],"tags":["oauth","api-key","credentials","authentication"],"backgroundTag":"missing-api-key","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"}