← Back to PRs

#7523: fix(auth): re-sync external CLI credentials on token revocation

by codeslayer44 open 2026-02-02 22:54 View on GitHub →
agents
## Summary - When an external CLI (e.g. Claude Code) refreshes its OAuth token independently, the old token is revoked (Anthropic uses single-use refresh tokens). OpenClaw's stored copy becomes invalid, causing `HTTP 403: permission_error: OAuth token has been revoked`. - The existing sync only re-reads from the CLI when the stored token is near-expiry, not when it's been revoked — revocation ≠ expiration. - Adds `resyncExternalCliOnAuthError()` that force-reads from external CLI credentials (bypassing the 15-minute TTL cache) when an auth error is detected, and retries with fresh tokens before marking the profile as failed. - Also logs a warning when the write-back to Claude CLI silently returns `false` (file missing or structure invalid) instead of swallowing the failure. ## Changes - **`external-cli-sync.ts`**: New `resyncExternalCliOnAuthError()` — force re-reads from Claude CLI / Qwen CLI / MiniMax CLI on auth errors, applies fresh tokens if different and still valid. - **`auth-profiles.ts`**: Barrel export for the new function. - **`run.ts`**: In both prompt-error and assistant-error paths, attempts re-sync before marking auth failure and rotating profiles. If fresh tokens are found, re-applies and retries. - **`oauth.ts`**: Checks `writeClaudeCliCredentials()` return value and logs when write-back fails silently. ## Test plan - [x] `pnpm build` passes - [x] `pnpm check` passes (lint clean on changed files) - [x] `pnpm test` — 881 tests pass across 73 test files - [ ] Manually verify: revoke token in Claude CLI, confirm OpenClaw recovers immediately instead of entering cooldown 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> PR adds a recovery path when OpenClaw hits OAuth `permission_error` due to token revocation from external CLIs (Claude Code/Qwen/MiniMax). It introduces a `resyncExternalCliOnAuthError()` that bypasses the existing TTL cache to force re-reading external CLI credential files, then updates the active profile tokens and retries before marking a profile as failed/rotating. It also logs when `writeClaudeCliCredentials()` returns `false` (previously silent), improving observability around failed write-back. These changes fit into the existing auth profile sync flow by extending `external-cli-sync.ts`’s read/write integration and hooking the runner’s error handling in `pi-embedded-runner/run.ts` so that revocation (a non-expiry failure mode) triggers a one-time refresh from the external source rather than immediately putting the profile into cooldown. <h3>Confidence Score: 4/5</h3> - This PR is generally safe to merge and improves recovery from external CLI token revocation, with a small logic edge case around token re-sync skipping updates when only expiry changes. - Core changes are localized and follow existing patterns (force-read external CLI creds on auth errors, retry before marking failures). The main concern is the Claude token resync branch’s equality check ignoring expiry/metadata changes, which could cause missed updates in some environments. Minor observability issue from swallowing apply errors. - src/agents/auth-profiles/external-cli-sync.ts (Claude token resync logic); src/agents/pi-embedded-runner/run.ts (swallowed applyApiKeyInfo errors) <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs