[BUG] OAuth credentials shared across CLAUDE_CONFIG_DIR profiles causing data isolation failure (compliance risk)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code uses the same macOS Keychain service name (Claude Code-credentials) for all profiles, regardless of CLAUDE_CONFIG_DIR setting. This causes OAuth token conflicts when using multiple accounts.
When two profiles with different OAuth accounts are used:
- Profile A logs in → stores tokens in Claude Code-credentials
- Profile B logs in → overwrites the same entry with different account's tokens
- Profile A tries to refresh → uses Profile B's refresh token → fails (wrong account)
Both profiles eventually require re-login
What Should Happen?
Keychain entries should be namespaced by config directory or account UUID to allow multiple OAuth accounts to coexist:
Claude Code-credentials-{md5(CLAUDE_CONFIG_DIR)[:8]}
# or
Claude Code-credentials-{accountUuid[:8]}
Why profile separation matters (business/security case):
- Work profile: Access to company systems, customer PII, proprietary code, strategic documents - subject to enterprise data retention and compliance policies
- Personal profile: Access to personal health information, family data, private projects - should not flow through work-governed systems
This is a compliance issue, not just an inconvenience. When OAuth tokens collide, users cannot guarantee which account processed which data. Personal health information or family data may inadvertently flow through a work account subject to enterprise audit/retention, or vice versa. For users handling sensitive data under GDPR, HIPAA, or SOC2 requirements, this lack of isolation creates real compliance risk.
Error Messages/Logs
When one profile's tokens are overwritten by another:
2026-01-22T23:50:57.658Z [ERROR] e3T: e3T: Invalid refresh token
2026-01-23T00:10:02.518Z [ERROR] e3T: e3T: Invalid refresh token
Followed by token expiration:
2026-01-23T22:40:06.814Z [ERROR] Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."}}
Steps to Reproduce
- Set up two profiles with different
CLAUDE_CONFIG_DIRvalues pointing to different directories - Login to Profile A with OAuth Account A (
/login) - Login to Profile B with OAuth Account B (
/login) - Use Profile A for a few hours
- Observe "Invalid refresh token" errors in debug logs (
~/.claude-work/debug/) - Eventually both profiles require
/loginagain (~8 hours)
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.19
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
Related Issues:
- #19456 - OAuth token refresh fails due to Keychain permission errors (my earlier report - the ACL issue is separate but compounds this problem)
- #15670 - CLAUDE_CONFIG_DIR doesn't completely isolate installations (same class of isolation bugs)
- #16103 - Cannot resume sessions when using CLAUDE_CONFIG_DIR
- #3833 - CLAUDE_CONFIG_DIR behavior unclear
Workaround:
Use API key authentication for one profile to avoid OAuth collision:
aclaude() {
export ANTHROPIC_API_KEY=$(cat ~/.secrets/anthropic-api-key)
CLAUDE_CONFIG_DIR=~/.claude-work command claude "$@"
unset ANTHROPIC_API_KEY
}
This is not a viable workaround for me though as we have an Enterprise subscription to Claude Code and I have a Claude Code subscription. API key access just significantly increases cost/wastage.
6 Comments
+1
I have a Personal and Team plan, I want to use them on the same machine so I created a small helper tool for macOS - Claude-Identity-Manager - but stumbled upon this limitation so for now I'm stuck and can't complete the tool.
+1
Same situation as above. Personal Max 20x subscription and now I've gotten my company to purchase a corporate Anthropic account. I want to use Claude Code with the appropriate account based on which project I am, and planned to use direnv to manage that, but this bug makes it impossible.
+1
Allowing per
CLAUDE_CONFIG_DIRauthentication is a really important feature, especially as Claude becomes used more in the workplace. It's the only way we can use effectively use our personal Claude accounts as well as our work accounts.This works already for Codex without issue (
CODEX_HOME).This actually seems to work for me. My work Claude account created a separate entry in Keychain "Claude Code-credentials-#######" with a unique hash, and I am able to use personal and work Claude Code accounts with different CLAUDE_CONFIG_DIRs easily. (I am using direnv to automatically set the correct Claude Code account per project.)
Thanks @devondragon! Very interesting. Are you on MacOS?
It looks like the namespacing fix has actually shipped — I can confirm it works on v2.1.56. Each
CLAUDE_CONFIG_DIRnow gets its own keychain entry using the first 8 characters of SHA-256 of the config dir path:Each entry has its own independent OAuth session with separate access tokens, refresh tokens, and expiry times. So the namespacing part of this issue is resolved.
However, the namespaced entries are created with a macOS Keychain ACL that prevents Claude Code from reading them after a restart:
Claude Code is signed as
com.anthropic.claude-code(TeamIdentifierQ6L2SF6YDW) — Anthropic-signed, not Apple-signed. After a reboot, the temporary creator privilege is gone and macOS blocks reads. You'll need to/loginagain in every project after each restart.This ACL issue is tracked in #19456. The namespacing fix is correct and working, but the ACL bug makes it effectively useless for persistence across restarts.
@nicholasjconn - yes on MacOS 15.7.4.
I do NOT seem to be having the ACL issue impacting me. I can't tell you why, but I have not had to use /login in many days, and I am using both Claude Code subscriptions automatically based on which project directory I run claude in (using my direnv managed CLAUDE_CONFIG_DIR env var).