[BUG] OAuth credentials shared across CLAUDE_CONFIG_DIR profiles causing data isolation failure (compliance risk)

Status Open
Reported on v2.1.19
Maintainer reply None cached
Activity 6 comments · opened Jan 24, 2026

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

  1. Set up two profiles with different CLAUDE_CONFIG_DIR values pointing to different directories
  2. Login to Profile A with OAuth Account A (/login)
  3. Login to Profile B with OAuth Account B (/login)
  4. Use Profile A for a few hours
  5. Observe "Invalid refresh token" errors in debug logs (~/.claude-work/debug/)
  6. Eventually both profiles require /login again (~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.

View original on GitHub ↗

6 Comments

stormychel · 7 months ago

+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.

devondragon · 6 months ago

+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.

nicholasjconn · 6 months ago

+1
Allowing per CLAUDE_CONFIG_DIR authentication 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).

devondragon · 6 months ago

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.)

nicholasjconn · 6 months ago

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_DIR now gets its own keychain entry using the first 8 characters of SHA-256 of the config dir path:

Claude Code-credentials                   ← legacy global entry
Claude Code-credentials-85be987d          ← sha256("<repo-a>/.claude-config")[:8]
Claude Code-credentials-806dff44          ← sha256("<repo-b>/.claude-config")[:8]

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:

entry 1 (decrypt/read):
    applications (1): /usr/bin/security        ← only Apple's security CLI

entry 3 (partition_id):
    description: apple-tool:                    ← only Apple-signed binaries

Claude Code is signed as com.anthropic.claude-code (TeamIdentifier Q6L2SF6YDW) — Anthropic-signed, not Apple-signed. After a reboot, the temporary creator privilege is gone and macOS blocks reads. You'll need to /login again 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.

devondragon · 6 months ago

@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).