Claude Code stops working and reports that your credentials are no longer valid. Depending on where the failure occurs, you will see one of these:
Your session has expired. Please run /login to sign in again.
Failed to authenticate: OAuth session expired and could not be refreshed
OAuth token expired and refresh failed (re-login required)
All three describe the same condition. The token Claude Code holds is dead, and the automatic refresh that normally renews it in the background was refused.
Why This Happens
When you sign in, Claude Code receives a short-lived access token and a longer-lived refresh token. The access token expires routinely, and Claude Code exchanges the refresh token for a new one without telling you. That silent renewal is why you can normally go weeks without seeing a login prompt.
You only see this error when the refresh itself fails. That happens for a handful of reasons:
- The session was revoked. Changing your password, signing out of claude.ai, or an administrator terminating sessions invalidates the refresh token everywhere.
- The machine was offline or asleep too long. If the refresh token itself ages out before the client can use it, there is nothing left to renew.
- The stored credential is corrupt or unreadable. A partially written credentials file, or a macOS Keychain that is locked or not writable, means Claude Code cannot read or persist tokens.
- A conflicting API key. An
ANTHROPIC_API_KEYin your environment competes with subscription login and can leave authentication in an inconsistent state. - A badly wrong system clock. Token validity is time-bound; a clock off by hours makes a valid token look expired.
Fix 1: Log In Again
Start here. Inside a Claude Code session:
/login
Your browser opens for the OAuth flow. Complete it, return to the terminal, and the session should resume.
This must be run from an interactive terminal — Claude Code will refuse the flow otherwise, since it needs to open a browser and wait for you.
Fix 2: Log Out First, Then Log In
If /login alone does not stick, the stored credential is likely stale rather than merely expired. Discard it explicitly:
/logout
/login
/logout signs you out of your Anthropic account and clears the cached credential, so the next login writes a completely fresh token instead of trying to reconcile a broken one. This two-step cycle resolves most cases that a bare /login does not.
Fix 3: Remove a Conflicting API Key
This is the most common reason the error returns immediately after a seemingly successful login. If ANTHROPIC_API_KEY is set, Claude Code may use it instead of your subscription session — and it will say so directly, telling you to unset the variable and run /login to sign in with your claude.ai account.
Check what is set:
env | grep -E "ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN"
Clear it and retry:
unset ANTHROPIC_API_KEY
unset ANTHROPIC_AUTH_TOKEN
claude
If that fixes it, remove the export from your shell profile as well — ~/.zshrc, ~/.bashrc or ~/.profile — otherwise it returns the next time you open a terminal:
grep -rn "ANTHROPIC_API_KEY" ~/.zshrc ~/.bashrc ~/.profile 2>/dev/null
Note that Claude Code also supports an apiKeyHelper setting, which can reintroduce a key even when the environment looks clean. Check your settings if the variable is genuinely gone but the behaviour persists.
Fix 4: Fix Credential Storage
Claude Code needs somewhere writable to persist a refreshed token. If it cannot write, every launch looks like a fresh expiry.
On macOS, credentials live in the login Keychain. Claude Code reports distinct errors — Keychain access denied or Keychain is not writable — when this is the problem. Unlock the login keychain in Keychain Access, confirm it is not set to lock automatically after a short idle period, and approve the access prompt when it appears.
On Linux and Windows, credentials are stored in a .credentials.json file under your Claude directory:
ls -la ~/.claude/.credentials.json
If the file is owned by root — usually the legacy of an installation run with sudo — Claude Code cannot rewrite it:
sudo chown $(whoami) ~/.claude/.credentials.json
chmod 600 ~/.claude/.credentials.json
As a last resort, delete the file and log in again to regenerate it:
rm ~/.claude/.credentials.json
claude
# then: /login
For a full map of where Claude Code keeps its state, see where configuration files are stored.
Fix 5: Check the System Clock
A clock that is significantly wrong makes valid tokens appear expired and can break the TLS handshake outright.
# macOS / Linux
date
# Force a time sync on macOS
sudo sntp -sS time.apple.com
# On Linux with systemd
sudo timedatectl set-ntp true
This is a rare cause on a laptop, but a common one in virtual machines and containers that have been suspended and resumed.
Fix 6: Rule Out a Proxy or Firewall
If the OAuth callback cannot reach Anthropic, login appears to succeed in the browser but never completes in the terminal. Behind a corporate proxy:
export HTTPS_PROXY="http://proxy.company.com:8080"
export HTTP_PROXY="http://proxy.company.com:8080"
claude
# then: /login
TLS-inspecting proxies are a frequent culprit here, since they present their own certificate to the client. If you can authenticate on a personal network but not on the corporate one, the network path is the problem rather than your credentials — see fixing permission and authentication errors for related network troubleshooting.
Verify the Fix
Confirm you are actually authenticated rather than merely unblocked:
/status
This shows the version, current model, account and API connectivity in one view. A populated account line and working connectivity means the token is valid.
For a broader check of the installation:
claude doctor
Then send a short message. A normal response confirms the session is live.
Prevention
- Do not mix authentication methods. Pick either subscription login or an API key on a given machine. Keeping
ANTHROPIC_API_KEYset "just in case" while logging in with claude.ai is the single most common cause of recurring authentication trouble. - Never install with sudo. Root-owned credentials and config files cause failures that look like expiry but are permission problems.
- Use API keys for anything headless. CI runners, servers and containers cannot complete an interactive OAuth flow. Issue a key from the Anthropic console for those environments.
- Re-authenticate deliberately after a password change. Changing your password invalidates existing sessions, so run
/loginonce afterwards instead of waiting to be interrupted mid-task. - Keep clocks synced on VMs and containers that get suspended.
Related Guides
- Fixing Claude Code permission errors
- Where Claude Code configuration files are stored
- Claude Code rate limits and reset times — the different error you get when authenticated but out of allowance