{"record":{"id":"05913a6404b81306","repo":"Kuberwastaken/claurst","slug":"login-succeeded-but-could-not-obtain-a-usable-cred","errorCode":null,"errorMessage":"Login succeeded but could not obtain a usable credential","messagePattern":"Login succeeded but could not obtain a usable credential","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/cli/src/oauth_flow.rs","lineNumber":248,"sourceCode":"        expires_at_ms: Some(expires_at_ms),\r\n        scopes: scopes.clone(),\r\n        account_uuid,\r\n        email,\r\n        organization_uuid,\r\n        subscription_type: None,\r\n        api_key: api_key.clone(),\r\n    };\r\n    tokens\r\n        .save_and_register(label)\r\n        .await\r\n        .context(\"Failed to save OAuth tokens\")?;\r\n\r\n    let (credential, use_bearer_auth) = if uses_bearer {\r\n        (token_resp.access_token.clone(), true)\r\n    } else if let Some(key) = api_key {\r\n        (key, false)\r\n    } else {\r\n        bail!(\"Login succeeded but could not obtain a usable credential\")\r\n    };\r\n\r\n    Ok(LoginResult { credential, use_bearer_auth, tokens })\r\n}\r\n\r\n// ---- Helpers ----------------------------------------------------------------\r\n\r\n/// Attempt to open the URL in the system default browser (best-effort).\r\nfn try_open_browser(url: &str) {\r\n    #[cfg(target_os = \"windows\")]\r\n    {\r\n        // Use PowerShell to safely open URLs containing special characters (& etc.)\r\n        let ps_cmd = format!(\"Start-Process '{}'\", url.replace('\\'', \"''\"));\r\n        let _ = std::process::Command::new(\"powershell\")\r\n            .args([\"-NoProfile\", \"-NonInteractive\", \"-Command\", &ps_cmd])\r\n            .stdin(std::process::Stdio::null())\r\n            .stdout(std::process::Stdio::null())\r\n            .stderr(std::process::Stdio::null())\r","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/cli/src/oauth_flow.rs#L230-L266","documentation":"This error is raised in finalize_login after the OAuth token exchange succeeded but no credential usable for API calls could be assembled. The flow grants either an inference-capable access token (bearer auth) or, for the Console flow, an API key minted via create_api_key. If the token response lacks the inference scope AND the API key creation failed (its error is swallowed into None with only a warning), nothing usable remains and login must abort.","triggerScenarios":"finalize_login receives a TokenExchangeResponse whose scope set does not contain CLAUDE_AI_INFERENCE_SCOPE (so uses_bearer is false), and the subsequent create_api_key call fails (network error, non-success HTTP status, missing raw_key), so api_key is None and the final if/else falls through to bail!.","commonSituations":"Developers hit this when the OAuth client is configured for the Console flow but the server rejects key creation (expired access token seconds after exchange, org policy forbidding API key creation, missing api-key creation scope), or when the upstream API returns an unexpected payload (e.g. raw_key absent) during a provider-side schema change.","solutions":["Check the warn! log line immediately above the error ('Failed to create API key from OAuth token: ...') — it contains the real root cause (HTTP status/body or parse error).","Re-run the login flow; transient network failures during key creation are common and a retry usually succeeds.","Verify the authenticated account/organization actually permits API key creation (org settings, billing active, role permissions).","Confirm the authorization URL requests the intended scopes; if you expect bearer auth, ensure the inference scope (CLAUDE_AI_INFERENCE_SCOPE) is granted.","If the server changed its CreateApiKeyResponse shape, update the parser in this crate to match the current wire format."],"exampleFix":"// before: key-creation failure is silently discarded, making the root cause opaque\nlet api_key = if !uses_bearer {\n    match create_api_key(&token_resp.access_token).await {\n        Ok(key) => Some(key),\n        Err(e) => {\n            warn!(\"Failed to create API key from OAuth token: {}\", e);\n            None\n        }\n    }\n} else { None };\n// after: surface the upstream reason in the final error\nlet api_key = if !uses_bearer {\n    create_api_key(&token_resp.access_token).await.ok()\n} else { None };\nif !uses_bearer && api_key.is_none() {\n    bail!(\"Login succeeded but could not obtain a usable credential: API key creation failed — see prior warning for the server response\");\n}","handlingStrategy":"fallback","validationCode":"// Before starting login, verify the flow can produce a credential\nlet scopes: Vec<&str> = auth_url_scopes.split_whitespace().collect();\nlet will_use_bearer = scopes.contains(oauth::CLAUDE_AI_INFERENCE_SCOPE);\nif !will_use_bearer {\n    ensure_console_key_creation_allowed()?; // org/policy check up front\n}","typeGuard":"fn usable_credential(uses_bearer: bool, api_key: &Option<String>) -> Option<(String, bool)> {\n    if uses_bearer {\n        Some((\"bearer\".to_string(), true))\n    } else {\n        api_key.clone().map(|k| (k, false))\n    }\n}","tryCatchPattern":"match run_oauth_login_flow_with_label(label).await {\n    Ok(result) => info!(\"logged in\"),\n    Err(e) if e.to_string().contains(\"usable credential\") => {\n        eprintln!(\"Login succeeded but key creation failed: {}\", e);\n        eprintln!(\"Check org API-key permissions and billing, then retry.\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Read the warn! log emitted during finalize_login — it carries the true root cause","Verify the account/organization permits API key creation before automating Console logins","Ensure the authorization request includes the inference scope if bearer auth is expected","Retry transient key-creation failures once before surfacing an error to the user"],"tags":["oauth","authentication","api-key","rust"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}