Skip to content

Keep the Claude login across container runs - #48

Merged
CrypticSwarm merged 1 commit into
masterfrom
claude-login-persistence
Aug 27, 2026
Merged

CrypticSwarm merged 1 commit into
masterfrom
claude-login-persistence

Conversation

@CrypticSwarm

Copy link
Copy Markdown
Owner

Claude's config dir is container-local, with the state that must outlive the run symlinked back into it from the shared home. .credentials.json sat on that allowlist, but credentials are written through a temp file and a rename: the first write replaced the link with a regular file in the container-local dir, and every refresh after that was stranded there. The shared home kept whatever predated the link's removal, so the next container started from a stale record and the login was invalid.

CLAUDE_SECURESTORAGE_CONFIG_DIR names the credential store apart from CLAUDE_CONFIG_DIR. The config dir stays container-local and keeps the isolation it was given; the store resolves to ~/.claude on the persistent mount, where the rename lands on a real file in a real directory. Claude takes its token-refresh lock in the store as well, so concurrent containers rotate the shared token one at a time instead of each holding a divergent copy of a rotating refresh token.

Also here:

  • .last-update-result.json leaves the state allowlist. It is rewritten by rename too, so the link never carried it.
  • The config merge excludes .credentials.json. The default user layer is the host's own ~/.claude, and the link whose removal used to clear the merged copy is gone.

The allowlist comment now states the rule an entry has to satisfy: a link holds only what claude writes in place.

tests/test_image_layout.py covers the store being named rather than linked, the store resolving inside the shared persistent home, and the merge exclusion.

Claude writes credentials through a temp file and a rename, so the
symlink standing in for .credentials.json was replaced by a regular file
on the first write. Every refresh after that landed in the
container-local config dir and died with the run, leaving the shared
home holding a stale record -- an invalid login on the next start.

CLAUDE_SECURESTORAGE_CONFIG_DIR names the credential store apart from
CLAUDE_CONFIG_DIR, so the config dir stays container-local while the
store resolves to ~/.claude on the persistent mount. Claude's
token-refresh lock lives in the store, so concurrent containers rotate
the shared token one at a time.

- .last-update-result.json leaves the allowlist for the same reason: it
  is rewritten by rename, so the link never carried it
- the config merge excludes .credentials.json -- the default user layer
  is the host's own ~/.claude, and the link that used to overwrite the
  merged copy is gone
@CrypticSwarm
CrypticSwarm merged commit 59ab992 into master Aug 27, 2026
4 checks passed
@CrypticSwarm
CrypticSwarm deleted the claude-login-persistence branch August 27, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant