Multiple concurrent CLI sessions cause auth failure on token refresh (race condition)
Description
When running multiple concurrent Claude Code CLI sessions (4-7+), all sessions simultaneously lose authentication when the OAuth access token expires (~8 hours). This forces a full re-login across every session.
Environment
- OS: macOS 15 (Darwin 25.4.0)
- Claude Code version: 2.1.109
- Auth method: claude.ai OAuth (
.credentials.jsonplaintext fallback) - Subscription: Claude Max
- Concurrent sessions: 4-7 interactive CLI sessions + desktop bridge + remote-control
Steps to Reproduce
- Log in to Claude Code CLI (
claude auth login) - Open 4+ concurrent CLI sessions (e.g., multiple terminal tabs or SSH sessions)
- Wait for the OAuth access token to expire (~8 hours)
- All sessions simultaneously fail with a login prompt
Expected Behavior
Token refresh should be coordinated so that only one session refreshes the token, and all other sessions pick up the new credentials from .credentials.json.
Actual Behavior
Multiple sessions race to refresh the expired access token simultaneously. If the OAuth server uses rotating refresh tokens:
- The first session to complete refresh succeeds and writes new tokens to
.credentials.json - All other sessions attempt to refresh with the now-invalidated old refresh token
- Those sessions fail and show a
/loginprompt - Result: all sessions except one are logged out simultaneously
Root Cause Analysis
All CLI sessions share a single ~/.claude/.credentials.json file with one refresh token. There is no file-locking or coordination mechanism to prevent concurrent refresh attempts. With rotating refresh tokens, only one refresh can succeed — the rest invalidate.
This is especially problematic for:
- Users running multiple terminal sessions
- SSH connections (no browser fallback for re-auth)
- Sessions bridged from the desktop app
Suggested Fix
- File-lock-based refresh coordination: Only one process performs the refresh, others wait and read the updated credentials
- Grace period for old refresh tokens: Accept the previous refresh token for a short window after rotation
- Per-session token management: Each CLI session maintains its own OAuth tokens
Additional Context
CLAUDE_CODE_OAUTH_TOKEN(fromclaude setup-token) returns 401 "OAuth authentication is currently not supported" — this headless auth path appears broken as well- Running
claude setup-tokenmay also revoke the existing refresh token server-side, causing all active sessions to fail once their access token expires
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗