#2123: fix(auth): sync from Claude CLI keychain before OAuth refresh
agents
Cluster:
Auth Improvements and Fixes
## Summary
Fixes #2036 - OAuth token race condition with Claude Code CLI
When both Claude Code CLI and Clawdbot share the same OAuth credentials, a race condition occurs:
1. Token expires at time H
2. Claude Code refreshes at H-5min → gets NEW tokens, writes to keychain
3. Clawdbot still has OLD tokens, tries to refresh → **fails** (old refresh token invalidated)
## Changes
- Before attempting OAuth refresh for the `claude-cli` profile, check if the Claude Code CLI keychain has fresher valid tokens
- If keychain has valid tokens, use those instead of attempting refresh
- On refresh failure, retry reading from keychain as a fallback
- Update the auth store with keychain credentials for future use
## Test plan
- [x] Build passes (`npm run build`)
- [x] Lint passes (`npm run lint`)
- [x] Auth-profiles unit tests pass (44 tests)
- [x] Manual end-to-end test with Telegram bot - confirmed working
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR mitigates an OAuth token refresh race for the `anthropic:claude-cli` profile when Claude Code CLI and another agent share credentials. It attempts to read fresher Claude CLI credentials (keychain/file via `readClaudeCliCredentials`) before performing an OAuth refresh, and also retries reading from the CLI credentials store after a refresh failure, updating the local auth profile store when it finds valid tokens.
The changes live in `src/agents/auth-profiles/oauth.ts`, specifically around `refreshOAuthTokenWithLock` and the refresh error-handling path in `resolveApiKeyForProfile`, and are intended to keep the auth store in sync with the external CLI credential source to avoid invalid refresh token failures.
<h3>Confidence Score: 3/5</h3>
- Mostly safe to merge once a compile/lint-breaking import issue is fixed.
- The functional change is scoped and follows existing auth-store patterns, but the current diff introduces a clear duplicate import that will fail TypeScript/lint, and the keychain sync paths should be re-verified after fixing that.
- src/agents/auth-profiles/oauth.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#7523: fix(auth): re-sync external CLI credentials on token revocation
by codeslayer44 · 2026-02-02
87.4%
#13484: feat(auth): restore Claude Code CLI OAuth credential sync
by joshpocock · 2026-02-10
86.2%
#10492: fix(auth): store Anthropic setup-token as type:oauth for auto-refresh
by sparck75 · 2026-02-06
84.3%
#8469: fix(auth): detect actual keychain account name when writing Claude ...
by adam-smeth · 2026-02-04
83.9%
#3196: docs: clarify auth-profiles.json format for Claude Max setup-tokens
by aadeina · 2026-01-28
82.3%
#4550: fix: sync google-gemini-cli-auth tokens from external CLI (#3803)
by SalimBinYousuf1 · 2026-01-30
82.1%
#5027: fix(auth): use correct OAuth credentials for google-gemini-cli refresh
by shayan919293 · 2026-01-30
81.5%
#3909: fix(auth): refresh all OAuth profiles per provider
by Daviey · 2026-01-29
80.5%
#21518: feat(auth): add Anthropic OAuth token refresh and fix external CLI ...
by maxtongwang · 2026-02-20
80.4%
#6400: fix: set correct mode for Anthropic OAuth auth (#2697)
by coupclawbot · 2026-02-01
80.0%