Skip to content

Support macOS login keychain for credentials (fixes #3)#5

Open
shackstack wants to merge 1 commit into
Leuconoe:mainfrom
shackstack:feat/macos-keychain-support
Open

Support macOS login keychain for credentials (fixes #3)#5
shackstack wants to merge 1 commit into
Leuconoe:mainfrom
shackstack:feat/macos-keychain-support

Conversation

@shackstack

Copy link
Copy Markdown

Problem

On macOS, Claude Code stores OAuth credentials in the login keychain (generic password, service Claude Code-credentials), not in ~/.claude/.credentials.json. Since the switcher only does file I/O for credentials, on a default macOS install:

  • cc-switch / sync fail with ENOENT: ... open '~/.claude/.credentials.json'
  • even a "successful" switch writes a file Claude Code never reads, so the active account never changes.

Fix

lib/store/io.cjs now bridges credential I/O to the keychain via the security CLI, but only when running on darwin, the credentials file is absent, and a keychain item exists. Otherwise behavior is unchanged.

  • read: security find-generic-password -s "Claude Code-credentials" -w
  • write: security add-generic-password -U -s "Claude Code-credentials" -a <acct> -w <json> (-U updates in place; <acct> taken from the existing item)
  • backup: dumps the current keychain value into the backup dir before overwriting (the existing file-backup step is a no-op when there's no file)

The keychain payload already has the exact shape the tool expects ({ claudeAiOauth, mcpOAuth }credentials.claudeAiOauth), so only the I/O layer changes — sync / list / switch logic is untouched.

Scope / safety

  • Activates only on macOS when the file is missing → no change for Linux/WSL/Windows or file-based macOS installs.
  • Pre-switch keychain backup added so a bad write is recoverable.

Testing

On macOS (Darwin, Node 18+), with credentials in the keychain and no .credentials.json:

  • cc-sync-oauth captures the current account
  • cc-switch lists accounts with usage
  • cc-switch <i> switches and Claude Code picks up the new account after restart
  • keychain remains valid afterwards (both claudeAiOauth and mcpOAuth preserved), and a keychain-credentials.*.bak is written before each switch

Fixes #3

On macOS, Claude Code stores OAuth credentials in the login keychain
(generic password, service "Claude Code-credentials") rather than in
~/.claude/.credentials.json. The switcher only did file I/O, so on a
default macOS install it failed with ENOENT on read, and a "successful"
switch wrote a file Claude Code never reads (active account unchanged).

Bridge credential I/O to the keychain via the `security` CLI when, on
darwin, the credentials file is absent but a keychain item exists:

- read:   security find-generic-password -s "Claude Code-credentials" -w
- write:  security add-generic-password -U -s "Claude Code-credentials"
          -a <acct> -w <json>
- backup: dump the current keychain value into the backup dir before
          overwriting (the file backup step is a no-op when no file exists)

The keychain payload already matches the expected shape
({ claudeAiOauth, mcpOAuth }), so only the I/O layer changes; sync / list
/ switch logic is untouched. Non-darwin and file-based macOS installs are
unaffected (the bridge only activates when the file is missing).

Fixes Leuconoe#3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS: credentials live in login keychain, not ~/.claude/.credentials.json — switcher fails

1 participant