Repository navigation
fix(claude): API-key Claude users are told they're not signed in - #25163
Conversation
…t signed in" Claude reports tokenSource "none" beside apiKeySource "ANTHROPIC_API_KEY" when it runs on an API key (environment or settings env). The startup check read only tokenSource, so it refused those chats as signed out. Refuse only when Claude reports no token source and no API-key source. Co-Authored-By: Claude <noreply@anthropic.com>
Review and QA summaryThe problem. People who run Claude with an API key instead of a Claude subscription login couldn't use Orca's native Claude chat. When a chat starts, Claude reports which credentials it found. For an API key it says "no login token" in one field and names the key in another field. Orca read only the first field, so it closed the chat with "Claude is not signed in for the selected account", even though What changes for users. API-key users can now open a native Claude chat and use it. That covers a key in the environment, a key in Claude's What the review checked and fixed
Deferred (pre-existing, not caused by this PR)
What was verified
What wasn't verified
|
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to Startup now accepts API-key sources reported by Claude while retaining the no-credentials refusal. Real API-key CLI behavior was not verified, but no concrete merge-blocking risk is established. Security Architecture ReviewSecurity architecture risk: ⚪ Minimal · up to The change recognizes API-key authentication without changing credential handling, tool permissions or session identity checks. No material security risk was found in the changed startup behavior. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
claudeInitializationAuthErrorno longer refuses when Claude reportstokenSource: "none"but names a credential inaccount.apiKeySource; it refuses only whenapiKeySourceis absent or"none". Verified against the bundled SDK types (SDKControlInitializeResponse.account: AccountInfo, with optionaltokenSource/apiKeySource/apiProvider), so the field is read from the right place for the initialize response.- New
it.eachcases inclaude-structured-session-startup.test.tspin the API-key, Console/login,apiKeyHelper,ANTHROPIC_AUTH_TOKENand third-party-provider accounts as starting, plus a negative case (apiKeySource: "none") that still refuses. The API-key rows genuinely fail on main, so the coverage is real.
Confirmed locally: claude-structured-session-startup.test.ts (16 passed) and claude-structured-session-adapter.test.ts (39 passed); oxlint and oxfmt clean. The refusal remains strictly narrower than before, and both apiKeySource branches (missing via the pre-existing test, "none" via the new one) stay covered.
One behavior worth being aware of, already framed as a follow-up in the PR body: a user with a configured but invalid key now opens the chat and fails at the first turn with Claude's raw auth error, since Orca does not yet map a turn's authentication_failed to its typed sign-in failure.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

ELI5
If you use Claude with an API key instead of a Claude subscription login, Orca's native chat told you "Claude is not signed in for the selected account" and would not open, even though
claudeworked fine for you in a terminal. Now the chat opens for API-key users. Someone with no credentials at all still gets the same sign-in message as before.What Changed
The problem. When a native (structured) Claude chat starts, Orca reads the account Claude reports in its first handshake answer (the "initialize" response). Orca treated
tokenSource: "none"as "not signed in". But Claude reportstokenSource: "none"for API-key users too, and names the key in a separate field,apiKeySource. Orca never read that field, so it shut down every chat that ran on anANTHROPIC_API_KEY.What a real Claude CLI (2.1.280) reports at initialize, captured in an isolated home with dummy credentials and no message sent:
accountat initializetokenSource: "none"ANTHROPIC_API_KEYin the environmenttokenSource: "none",apiKeySource: "ANTHROPIC_API_KEY"ANTHROPIC_API_KEYinsettings.jsonenvtokenSource: "none",apiKeySource: "ANTHROPIC_API_KEY"/login(from Claude's own source, not captured)tokenSource: "none",apiKeySource: "/login managed key"ANTHROPIC_AUTH_TOKEN(env, settings env, or withANTHROPIC_BASE_URL)tokenSource: "ANTHROPIC_AUTH_TOKEN"CLAUDE_CODE_OAUTH_TOKENtokenSource: "CLAUDE_CODE_OAUTH_TOKEN"apiKeyHelperin settingstokenSource: "apiKeyHelper",apiKeySource: "apiKeyHelper"apiProvider: "bedrock"/"vertex", notokenSourceSo the API-key rows were the only ones affected.
The user-facing change. A Claude API-key user who opens a native chat now gets a working chat instead of the "not signed in" failure. Nothing else changes: a user with no credentials still gets the same sign-in guidance at the same point.
The mechanism.
claudeInitializationAuthError(src/main/claude/claude-structured-init-proof.ts) now refuses only when Claude reports no token source and no API-key source (apiKeySourceabsent or"none"). It still reads only the initialize answer Orca already receives. There is no new probe, setting or stored state.Why
authentication_failedreply, which is how the common pattern detects a signed-out Claude. Today that would be a regression: Orca doesn't read that reply yet, so a signed-out user's first message would show Claude's raw "Not logged in · Please run /login" twice (once as a reply, once as an error row) instead of Orca's sign-in message. Difference from the common pattern (temporary): Orca still refuses at open when Claude reports no credentials at all. That keeps today's message for those users, and it can no longer misfire on a configured key. Follow-up: handle a turn'sauthentication_failedas Orca's typed "not signed in" failure, then remove the open-time check. That follow-up changes what a signed-out user sees (they'd learn at their first message, not at open), so it needs its own decision.Linked Issue
Found while building #25152, whose isolated test of the Claude SDK with
ANTHROPIC_API_KEYset reportedtokenSource: "none"withapiKeySource: "ANTHROPIC_API_KEY".Visual Proof
b354aab18e1, main at this PR's merge base)3401ae76fbc, this PR)tokenSource: "none"account, as in A)Hidden, isolated e2e builds on the M4Air test Mac, driven over CDP by a Grok QA agent.
claudeis a stand-in that answers initialize withaccount: {tokenSource: "none", apiKeySource: "ANTHROPIC_API_KEY"}for A and{tokenSource: "none"}for B; no real Claude or account was used. The "Enjoying Orca?" card in the A-after shot is the existing GitHub-star prompt that follows a first successful chat turn; this PR does not add it.Testing
src/main/claude/claude-structured-session-startup.test.ts: new cases using the account shapes in the table above. The API-key and Console/logincases fail on main and pass here; the others (auth token, helper, Bedrock) pin the cases that already worked; "apiKeySource: "none"" still refuses.Existing "not signed in" tests still pass: adapter, runtime integration (
claude-structured-session-integration.test.ts), and command lifecycle: 104 tests on the final head, after merging current main.Node typecheck, oxlint, format check and the changed-code quality gate all pass.
Real Claude CLI suite (
ORCA_REAL_CLAUDE_CLI_TEST=1, subscription login): 10/10 passed on the final head.The capture in the table: a script that drives the Claude SDK directly under
env -i, with a temporaryHOMEandCLAUDE_CONFIG_DIRand dummy credentials only. It sends no message, so nothing reaches the network with a key.I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Cross-platform: a pure check on the handshake answer, no platform code. SSH/remote: runs wherever Claude runs, on the same answer. Mobile and paired clients: no wire change; they just stop receiving a false "not signed in" failure. Performance: none.
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)