Skip to content

Frequent re-authentication required with multiple concurrent Claude Code sessions (OAuth refresh token race condition) #24317

@pfallonjensen

Description

@pfallonjensen

Bug: Frequent re-authentication required with multiple concurrent Claude Code sessions

Description

Claude Code requires re-authentication (browser OAuth flow) multiple times per day, even though a valid refresh token exists in ~/.claude/.credentials.json. This appears to be caused by a race condition when multiple concurrent Claude Code sessions attempt to refresh the same OAuth token.

Environment

  • Claude Code version: 2.1.37
  • OS: macOS 15.7.1 (Apple Silicon, arm64)
  • Subscription: Team (Max 5x tier)
  • Concurrent sessions: 7-12 active Claude Code processes at any given time

Steps to Reproduce

  1. Open 5+ terminal tabs, each running claude in different project directories
  2. Work normally across sessions throughout the day
  3. After some time (typically a few hours), one or more sessions will prompt: /login to re-authenticate
  4. Re-authenticating in one session may cause other sessions to lose their auth shortly after

Expected Behavior

The refresh token should silently renew the access token without user interaction. Multiple concurrent sessions sharing the same credentials file should coordinate token refresh (e.g., file-based locking, or re-reading the credentials file before attempting refresh).

Actual Behavior

Sessions frequently lose authentication and require a full browser-based OAuth re-login. This happens multiple times per day with several concurrent sessions open.

Root Cause Analysis

The credentials file (~/.claude/.credentials.json) contains:

  • accessToken — short-lived (~15 hour expiry)
  • refreshToken — used to obtain new access tokens

OAuth refresh tokens are typically single-use: when one process uses the refresh token to get a new access/refresh token pair, the old refresh token is invalidated server-side. With N concurrent Claude Code processes:

  1. Process A's access token expires
  2. Process A uses the refresh token → gets new access token + new refresh token
  3. Process A writes new credentials to ~/.claude/.credentials.json
  4. Process B's access token also expires (or was already expired)
  5. Process B tries to use the old refresh token (which it read into memory at startup)
  6. Server rejects the old refresh token (already consumed by Process A)
  7. Process B prompts user to re-authenticate via browser

This race becomes increasingly likely with more concurrent sessions, as the window for token expiry overlap grows.

Impact

  • Disrupts workflow — interrupts active coding sessions to complete browser OAuth flow
  • Blocks headless/SSH use cases entirely — Claude Code cannot be used over SSH when re-auth is needed, because the OAuth flow opens a browser on the host machine. This makes remote access (e.g., from a mobile SSH client) unreliable.
  • Scales with usage — power users who keep multiple sessions open (different projects, different terminal tabs) are most affected

Suggested Fixes

  1. Re-read credentials from disk before refresh: Before attempting a token refresh, check if another process has already written a fresh token to the credentials file. If the file's expiresAt is in the future, use the new token instead of refreshing.

  2. File-based locking on refresh: Use a lockfile (~/.claude/.credentials.lock) to prevent concurrent refresh attempts. Only one process refreshes at a time; others wait and then read the refreshed token.

  3. Longer-lived refresh tokens: If the refresh token had a longer lifetime or was multi-use (not invalidated on first use), concurrent sessions could independently refresh without invalidating each other.

  4. In-memory token sharing: Use a local IPC mechanism (Unix socket, shared memory) so all Claude Code processes share a single token manager that handles refresh.

Workaround

Currently, the only workaround is to close stale Claude Code sessions to reduce the number of concurrent processes competing for token refresh. This is not ideal for users who work across multiple projects simultaneously.

An ANTHROPIC_API_KEY environment variable bypasses OAuth entirely but uses API billing instead of the subscription — not a real fix for subscription users.

Additional Context

This bug is particularly impactful for users building automation around Claude Code (e.g., LaunchAgent-triggered sessions, SSH-based remote access from mobile devices) where browser-based re-authentication is impossible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:macosIssue specifically occurs on macOS

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions