anthropics / anthropics/claude-code
CLAUDE_CONFIG_DIR set to the default path ($HOME/.claude) selects a different Keychain credential entry than leaving it unset, with no diagnosis
- Lingua principale
- Python
- Stelle
- 145k
- Fork
- 23.1k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
### What's Wrong?
Per the docs (Authentication → Credential management), setting `CLAUDE_CONFIG_DIR` keys the macOS Keychain entry to that directory, "so a session with a different `CLAUDE_CONFIG_DIR` reads a different entry." That's expected when the directory actually differs. But here the directory is byte-identical to the default — only whether the variable is textually present differs — and the result is a full loss of login, with nothing in `auth status` or the "Not logged in · Please run /login" message saying which credential store was consulted.
Any script or automation that forwards `CLAUDE_CONFIG_DIR` unconditionally (e.g. to pin a relocated install's root, or because it defensively re-sets `process.env` values) silently breaks auth for that child process the moment the parent never had the variable set in the first place.
### Steps to Reproduce
```bash
claude auth status
# → {"loggedIn": true, "authMethod": "claude.ai", ...}
CLAUDE_CONFIG_DIR="$HOME/.claude" claude auth status
# → {"loggedIn": false, "authMethod": "none"}
```
Variants that isolate it to the variable's literal presence/value, not path resolution:
```bash
CLAUDE_CONFIG_DIR="$HOME/.claude/" claude auth status # trailing slash → still false
CLAUDE_SECURESTORAGE_CONFIG_DIR="$HOME/.claude" claude auth status # → still false
```
(An unexpanded `CLAUDE_CONFIG_DIR='~/.claude'` also fails, but that's a genuinely different directory — `auth status` reports `projectsDirectory: "~/.claude/projects"`, literal tilde, unresolved — so it isn't a same-directory data point and is omitted here.)
Workaround, pinning the default credential store explicitly — restores login but not identity reporting:
```bash
CLAUDE_CONFIG_DIR="$HOME/.claude" CLAUDE_SECURESTORAGE_CONFIG_DIR="" claude auth status
# → {"loggedIn": true, "authMethod": "claude.ai", "email": null, "orgId": null, "orgName": null, "subscriptionType": "max"}
```
### Environment
- `claude --version`: 2.1.261 (npm install under Homebrew's node prefix)
- macOS 26.6.2 (arm64)
- OAuth subscription login (Claude.ai, Max plan); `~/.claude/.credentials.json` does not exist — Keychain-only credential store
- Regression status: unknown, not tested on earlier versions (per #79223, the CLI has recognized `CLAUDE_SECURESTORAGE_CONFIG_DIR` since roughly 2.1.144, which is the related-but-separate mechanism this report's `CLAUDE_CONFIG_DIR` keying appears to route through — not a claim about when `CLAUDE_CONFIG_DIR`'s own keying began)
### What Should Happen?
Primarily: make this diagnosable. `claude auth status` and the `--print` "Not logged in" path should report which credential store/Keychain entry was consulted (and that an explicit `CLAUDE_CONFIG_DIR` selects a different one than unset), instead of an undifferentiated "Not logged in · Please run /login". This should also be documented alongside the existing `CLAUDE_CONFIG_DIR` docs, not only inferable from `CLAUDE_SECURESTORAGE_CONFIG_DIR` behavior.
Alternative (one clause): resolve an explicit `CLAUDE_CONFIG_DIR` that is byte-identical to the default to the same credential entry as leaving it unset. (This has a migration wrinkle — anyone who already logged in under the explicit path has a credential in the other slot — so the diagnosability fix above is the safer primary ask.)
### Related
- #87447 — "Repro C" in that issue is this same unset-vs-explicit-default discrepancy (seen there as `loggedIn:true` with null identity on Windows' plaintext credential file; here as a clean `loggedIn:false` on macOS Keychain). Buried as the third of three repros in a broader issue about a different primary complaint.
- #79223 — documents `CLAUDE_SECURESTORAGE_CONFIG_DIR` behavior in detail, including "setting the variable to your default config directory's absolute path selects a different, empty credential store, which presents as a lost login" and "an empty value pins the default credential store." This issue's repro matches that description exactly; #79223 is a docs request for the sibling variable, not a report against `CLAUDE_CONFIG_DIR`'s own behavior or the error message.
- #88601 — describes per-config-dir credential isolation as current behavior (different directories get different Keychain items, `Claude Code-credentials-`); closed by its own author, not a maintainer statement of intent. Not in conflict with this report, which is about explicit-vs-unset for the *same* directory.
- #84275 / #90527 — a different, adjacent defect (hash-suffixed Keychain items accumulating daily, never cleaned up), not this one.
### Additional context
Found this while debugging a background automation that unconditionally forwarded `CLAUDE_CONFIG_DIR` to a spawned child process — even when the parent never had the variable set, the forwarding code still injected the resolved-to-default path, reproducing this exactly. Only forwarding the variable when the parent actually had it set resolved it.
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
Start by reproducing the unset and explicit-default CLAUDE_CONFIG_DIR commands through the auth status and --print entry points. Read the Authentication → Credential management documentation and related issue #79223, then trace how the credential store is selected. Done means auth status and --print identify the consulted store, with documentation updated, or equivalent paths consistently select one credential entry.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- macos, python, shell
- Ambito
- authentication, cli, security
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Attiva
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 45/100