[FEATURE] Supported way to share/copy credentials between CLAUDE_CONFIG_DIR profiles (macOS Keychain makes file-level workarounds impossible)

Status Fixed / completed
Reported on v2.1.238
Maintainer reply None cached
Activity 1 comment · opened Aug 21, 2026 · closed Aug 21, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single feature request
  • [x] I am using the latest version of Claude Code

What problem does this solve?

CLAUDE_CONFIG_DIR is an excellent mechanism for running several harnesses —
different CLAUDE.md, skills, agents, and permission sets — side by side on one
machine. Isolation works well. But credentials are per config dir and there is
no supported way to reuse one identity across profiles
, so every new profile
costs an interactive browser login, and every profile is a separate auth
identity thereafter.

For a single human with a single Claude subscription running N harnesses, that is
N logins for one account. It is the main friction in an otherwise clean feature,
and it discourages exactly the use case config-dir isolation enables: cheap,
disposable, experiment-scoped profiles.

Measured behaviour (macOS, Claude Code 2.1.238)

$ claude auth status
  "loggedIn": true,  "authMethod": "claude.ai"

$ CLAUDE_CONFIG_DIR=~/.harness/claude/swe claude auth status
  "loggedIn": false, "authMethod": "none"

There is no file-level workaround, and the failure mode of trying is worse than
the original problem:

  1. On macOS the authoritative credential is a Keychain generic-password item,

not ~/.claude/.credentials.json. In my case the JSON file was a stale
leftover whose access token had expired a week earlier while the default root
kept working perfectly — so the file is not even a reliable mirror of the live
credential. The item also appears to be namespaced per config dir: the default
root uses Claude Code-credentials, while another config dir gets
Claude Code-credentials-<first 8 hex of sha256 of its absolute path>. There
is therefore no shared record a second profile could be pointed at — each
config dir has its own deterministic slot.

  1. Symlinking or copying .credentials.json into a profile makes the session

start and then die with OAuth session expired and could not be
refreshed
, instead of failing honestly at auth status. Hand-copying a live
credential between slots carries a separate hazard: if the copy refreshes, it
writes new tokens to its own slot and the source's refresh token may be
revoked server-side — and revocation is not local state, so there is no local
rollback for a broken source login.

  1. Seeding userID / oauthAccount / hasAvailableSubscription into the

profile's .claude.json does not authenticate it.

  1. claude auth login offers only --claudeai --console --email --sso — no

non-interactive path — so this cannot be scripted for provisioning either.

Net effect: a fresh profile can only be authenticated by a human with a browser,
one profile at a time.

The per-config-dir item naming above was inferred by matching Keychain item names
against hashes of config dir paths, not read from documentation, so I would not
want to script against it — which is much of why I am asking for a supported
command rather than building this myself.

Proposed solution

Any one of these would resolve it; roughly in order of preference:

  1. An explicit copy/link command, e.g.

claude auth copy --from ~/.claude --to $CLAUDE_CONFIG_DIR
(or claude auth share), which does the Keychain-aware thing on each platform
and handles refresh-token rotation correctly across slots.

  1. Opt-in credential inheritance: a setting such as

"auth": { "inheritFrom": "~/.claude" } in a profile's settings.json, or an
env var like CLAUDE_CREDENTIALS_DIR that decouples where credentials live
from where config lives. Config isolation and credential isolation are
genuinely separate concerns, and today they are welded together.

  1. A documented, supported non-interactive login (token in, credential

stored) so profile provisioning can at least be scripted.

Option 2 is the smallest conceptual change: keep the default as today
(credentials follow the config dir), and let a profile explicitly declare that it
shares an identity.

What I'd expect either way

  • Failing honestly. If a profile is unauthenticated, auth status should say so

(it does) and nothing should be able to put it into the misleading
"expired session" state via file manipulation.

  • Documentation in the CLAUDE_CONFIG_DIR section stating plainly that

credentials do not transfer, and what the supported path is. This is currently
learned by trial and error.

Related

  • #47661 — the Linux/WSL2 mirror image: credentials there fail to isolate

because there is no Keychain. Both issues point at the same underlying design
question of where credentials live relative to the config dir.

  • #80791 — .claude at/above cwd treated as project scope over a

CLAUDE_CONFIG_DIR profile. (Unrelated cause; noting it as adjacent
config-dir behaviour. I could not reproduce that one on 2.1.238.)

Environment

  • Claude Code 2.1.238
  • macOS (Darwin 24.4.0), arm64
  • Auth method: claude.ai (team)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗