Claude subscription Connect always fails on macOS: isolated login token is in Keychain, not .credentials.json
Summary
On macOS, connecting a Claude subscription through the Connect a model wizard always fails with:
Could not verify the local subscription. Run the sign-in command shown for this connection, finish signing in, then try Connect again.
This happens even after claude auth login completes successfully with the command the wizard shows.
Cause
The wizard runs the login with an isolated home:
(export CLAUDE_CONFIG_DIR='<instance>/ai-local-logins/<attemptId>' && mkdir -p "$CLAUDE_CONFIG_DIR" && claude auth login)
On macOS, Claude Code doesn't write the OAuth credential to $CLAUDE_CONFIG_DIR/.credentials.json. It stores it in the login Keychain under a service name derived from the config dir:
Claude Code-credentials-<first 8 hex chars of sha256(CLAUDE_CONFIG_DIR)>
After a successful login, the login home contains .claude.json (with oauthAccount populated) but no .credentials.json.
readVerifiedLocalAiCredential (server/src/services/local-ai-credentials.ts) only reads .credentials.json / credentials.json when loginHome is set. The Keychain path in readClaudeToken({ allowKeychain: true }) is deliberately skipped for a custom config dir. So the token is never found, and the route returns the error above.
Repro
- macOS, Claude Code 2.1.x, Paperclip in
authenticatedmode. - Onboarding → Connect a model → Claude (Subscription).
- Run the displayed command and finish browser sign-in.
- Click Connect → error.
ls <loginHome>shows.claude.jsonandbackups/, but no.credentials.json. security dump-keychain | grep -o '"svce"<blob>="Claude Code-credentials[^"]*"'listsClaude Code-credentials-<hash>, where<hash>issha256(loginHome).slice(0, 8).
Proposed fix
When loginHome is set and no credentials file exists, read only that home's own Keychain item (Claude Code-credentials-${sha256(loginHome).slice(0,8)}), never the unsuffixed host-account item. That keeps the isolation guarantee: an isolated login still can't resolve to the operator's own account.
I have a small patch for this:
readClaudeTokenFromConfigDirKeychain(configDir)added topackages/adapters/claude-local/src/server/quota.ts(darwin-only, errors swallowed so no credential material surfaces).local-ai-credentials.tsfalls back to it after the file lookup.- Tests: the exact service name for a known path, no Keychain access off macOS, subprocess errors not surfaced, file preferred over Keychain, and never calling the host-account
readClaudeToken.
Happy to open a PR.
Generated with Claude Code
Source: paperclipai/paperclip