anthropics / anthropics/claude-code

[Bug] Future-dated OAuth refresh lock blocks token refresh indefinitely

Open
#95,739 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:auth bug has repro platform:linux
Dominant language
TypeScript
Stars
147k
Forks
24k
PR merge metrics
PR metrics pending

Description

Bug Description
[bug] A future-dated ~/.claude/.oauth_refresh.lock never expires and blocks all token refresh

What happened: On a host that corrects its clock backward ~4h shortly after boot, a token refresh started before the correction and failed. It left ~/.claude/.oauth_refresh.lock with an mtime ~4h in the future. Lock staleness looks age-based, so now - mtime stayed negative and the lock never expired: the daemon's 30s keychain re-check never recovered, and every claude invocation returned "Failed to refresh OAuth token: another Claude Code process is refreshing it or exited mid-refresh. This is usually transient; retry in a minute..." with no other Claude Code process running. rmdir on the empty lock directory restored refresh immediately using the same stored credentials. Expected: a lock whose mtime is in the future is treated as invalid, or the lock is keyed on pid/boot-id rather than age.

Two things made this hard to diagnose: ~/.claude/daemon-auth-status.json still read {"status":"auth_required"} after the refresh succeeded (it is not rewritten on recovery), and claude auth status reported loggedIn: true throughout, since it reads the stored credential without checking expiry.

What the user said: "Why is [the containerized session] logged out again? Is it DNS, firewall, or other similar issues again?"

Repro: Have the system clock step backward while a token refresh is in flight (container or VM boot, NTP correction, host resume). The lock is then stamped in the future and blocks every refresh until real time passes that mtime.

Evidence: CLI 2.1.267. Three cold boots, same daemon.log signature: refresh failed 2.510s / 2.535s / 2.512s after starting, each followed by "auth: headless daemon cannot complete OAuth". Lock mtime observed ~4h ahead of wall clock.

Cause: Verified in-session — removing the future-dated lock restored refresh with unchanged credentials, so the refresh token was valid the whole time and the lock was the only blocker.

Environment Info

  • Platform: linux
  • Terminal: kitty
  • Version: 2.1.267
  • Feedback ID: f89c1aac-f29d-4b5e-8bee-3c382e5acd9e

Errors

[]

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the daemon's OAuth refresh lock handling and the staleness check for ~/.claude/.oauth_refresh.lock. Reproduce a future-dated lock after a backward clock step, then verify refresh recovers without manually removing the lock; also check the observed daemon-auth-status.json and auth status behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authentication, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.