#10492: fix(auth): store Anthropic setup-token as type:oauth for auto-refresh
commands
stale
Cluster:
Auth Improvements and Fixes
## Summary
The `setup-token` authentication flow only stores Anthropic credentials as `type: "token"` (static, non-refreshable). When the OAuth access token expires (~1 hour), OpenClaw cannot auto-refresh it, causing cascading HTTP 401 failures that put the entire Anthropic provider into cooldown with no automatic recovery path.
This PR modifies the setup-token flow to support storing credentials as `type: "oauth"` with refresh tokens, enabling automatic token renewal.
## Problem
- Anthropic OAuth access tokens (`sk-ant-oat01-...`) expire after ~1 hour
- The `setup-token` flow stores them as `type: "token"` — a static, non-refreshable credential
- When the token expires, all Anthropic models become unavailable (cooldown cascade)
- No automatic recovery — requires manual re-authentication
- In multi-agent setups, expired tokens cause error message loops between agents
## Solution
Three-path credential storage in both the onboarding wizard and `models auth` command:
1. **Full JSON credentials** — User pastes `~/.claude/.credentials.json` contents → stored as `type: "oauth"` with access token, refresh token, and expiry. Best path: fully automatic refresh.
2. **Access token + refresh token** — User pastes the access token, then is prompted for an optional refresh token → stored as `type: "oauth"` with 1h default expiry.
3. **Access token only** (fallback) — No refresh token provided → falls back to original `type: "token"` behavior. Fully backward compatible.
## Changes
- **`src/commands/auth-token.ts`**: New `validateAnthropicRefreshToken()` and `tryParseClaudeCredentials()` functions. Updated `validateAnthropicSetupToken()` to also accept JSON credential blobs.
- **`src/commands/auth-choice.apply.anthropic.ts`**: Onboarding wizard now supports all three credential paths with updated prompts and tips.
- **`src/commands/models/auth.ts`**: Runtime `models auth` command with the same three-path logic.
- **`src/commands/auth-token.test.ts`**: 22 unit tests covering validation and parsing of refresh tokens, JSON credentials, and setup tokens.
## Test plan
- [x] All 22 new unit tests pass (`vitest run src/commands/auth-token.test.ts`)
- [x] TypeScript compiles cleanly (zero new errors in `src/`)
- [ ] Manual test: paste full `.credentials.json` during onboarding → verify `type: "oauth"` stored
- [ ] Manual test: paste access token + refresh token → verify `type: "oauth"` stored
- [ ] Manual test: paste access token only → verify `type: "token"` stored (backward compat)
- [ ] Verify auto-refresh works after token expiry with `type: "oauth"` credentials
## Related
- Fixes #9095 — Anthropic OAuth authentication fails with HTTP 401 invalid bearer token
- Related to #9938 — Anthropic OAuth tokens stopped working
- Related to #9141 — Configure wizard fails to save Anthropic setup token
- Complementary to #5988 — Claude CLI credential sync (addresses the CLI sync side)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
- Updates Anthropic `setup-token` flows (onboarding + `models auth`) to optionally store refreshable `type: "oauth"` credentials when a refresh token is available.
- Adds parsing/validation helpers for refresh tokens and full `~/.claude/.credentials.json` blobs, plus unit tests.
- Leaves the original access-token-only path in place by falling back to `type: "token"` storage when no refresh token is provided.
<h3>Confidence Score: 3/5</h3>
- This PR is close to mergeable, but there is a concrete credential-persistence bug in the new JSON/refresh handling paths.
- Core idea and wiring to `type: "oauth"` looks consistent with existing auth-profile refresh logic, and tests cover the helpers. However, both the onboarding wizard and `models auth setup-token` can persist a full JSON blob as a static token if JSON parsing fails and the user skips the refresh-token prompt, which will break authentication for that profile until manually fixed.
- src/commands/auth-choice.apply.anthropic.ts, src/commands/models/auth.ts, src/commands/auth-token.ts
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#6400: fix: set correct mode for Anthropic OAuth auth (#2697)
by coupclawbot · 2026-02-01
84.4%
#2123: fix(auth): sync from Claude CLI keychain before OAuth refresh
by jorge123255 · 2026-01-26
84.3%
#3196: docs: clarify auth-profiles.json format for Claude Max setup-tokens
by aadeina · 2026-01-28
83.3%
#13484: feat(auth): restore Claude Code CLI OAuth credential sync
by joshpocock · 2026-02-10
82.9%
#10108: fix: override stale Anthropic OAuth stealth headers for Opus 4.6
by CivilBooks · 2026-02-06
82.3%
#22105: feat(auth): add refreshable Anthropic OAuth login flow
by sauerdaniel · 2026-02-20
81.9%
#9163: Fix: Save Anthropic setup token to config file
by vishaltandale00 · 2026-02-04
81.4%
#7523: fix(auth): re-sync external CLI credentials on token revocation
by codeslayer44 · 2026-02-02
80.4%
#8805: [Bug Fix][AI-assisted] Refresh Copilot token before expiry and retr...
by Arthur742Ramos · 2026-02-04
79.7%
#21518: feat(auth): add Anthropic OAuth token refresh and fix external CLI ...
by maxtongwang · 2026-02-20
79.5%