fix(claude): Read the session from the macOS login keychain - #39
Conversation
load_claude() looked for ~/.claude/.credentials.json and, failing that, three hard-coded keyring pairs: cairn-code:oauth:claude, cairn-code:claude, and claude:credentials. macOS Claude Code writes none of them. It writes no credentials file at all, and keeps the OAuth session in the login keychain under the service "Claude Code-credentials", keyed by the OS username rather than a fixed account name. So every macOS install reported Claude as UNCONFIGURED while Linux and Windows, which do get the file, worked. Look the entry up by service alone. keyring::read() now takes an optional account: None drops -a on macOS and username on Linux, and falls back to the bare service as the target name on Windows. Guessing the username would be the alternative, and this crate has no business doing that. Take the live credential rather than the first one found, as load_grok() does for the same reason. Only Claude Code rewrites either copy, so a leftover credentials file from an older install would otherwise shadow the keychain entry it actually refreshes, and the refresh probe could never recover: it would refresh a store the loader had already decided to ignore. Refs #38
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe keyring API now supports service-only searches. Claude loading reads macOS keychain credentials, evaluates all available candidates, and selects a live token. Provider guidance and coverage were updated. ChangesClaude keyring support
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: 🔵 Low · up to Claude now reads macOS login-keychain credentials, but service-only matching could select the wrong Claude identity when multiple matching entries exist. The change is otherwise mergeable with explicit owner awareness or follow-up to define deterministic handling for duplicate entries. Sequence Diagram(s)sequenceDiagram
participant ClaudeLoader
participant CredentialsFile
participant Keyring
participant ClaudeParser
ClaudeLoader->>CredentialsFile: Read credentials file
ClaudeLoader->>Keyring: Read Claude Code-credentials by service
Keyring-->>ClaudeLoader: Return keyring credential
ClaudeLoader->>ClaudeParser: Parse all candidates
ClaudeParser-->>ClaudeLoader: Select live credential
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Full details: Linked Issues checkExplanation The changes address issue ✨ Finishing Touches📝 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 |
Summary
macOS Claude Code writes no
~/.claude/.credentials.json. It keeps the OAuthsession in the login keychain under the service
Claude Code-credentials, keyedby the OS username rather than a fixed account name.
load_claude()probed onlythat file and three fixed service/account pairs, so every macOS install reported
Claude as
UNCONFIGUREDwhile Linux and Windows, which do get the file, worked.Closes #38
Changes
keyring::read()takes an optional account.Nonematches on the servicealone: no
-aon macOS, nousernameon Linux, and the bare service as thetarget name on Windows. Guessing the username was the alternative, and this
crate has no business doing that.
load_claude()reads a newCLAUDE_KEYRING_ENTRIESlist led byClaude Code-credentials, and takes the live candidate viapick_live()rather than the first one found -- the same shape
load_grok()settled on inGrok reports HTTP 401 when a stale keyring entry shadows the CLI credential #36. A leftover credentials file from an older install would otherwise shadow
the keychain entry Claude Code actually refreshes, and the refresh probe could
not recover: it would refresh a store the loader had already decided to ignore.
Test plan
reads_the_claude_code_keyring_entry_keyed_by_os_usernameinjects a fakereader that answers only for the account-less macOS service. It fails on
mainand passes here.
cargo test: 161 passed.cargo clippy --all-targets: clean.limits status -p claudeon macOS now reports Session 22.0% (4h 8m) andWeekly 3.0% (6d 11h) against a live Pro account, in place of
UNCONFIGURED.