fix(auth): add Claude CLI to EXTERNAL_CLI_SYNC_PROVIDERS for automatic OAuth token sync#70902
Conversation
Greptile SummaryThis PR registers
Confidence Score: 3/5Not safe to merge without resolving the ClaudeCliCredential / OAuthCredential type incompatibility. There is a P1 type mismatch: ClaudeCliCredential includes a type: "token" variant that is not assignable to OAuthCredential. This would cause a TypeScript compile error and a silent runtime bug if a token credential is ever returned. A one-line guard is all that is needed to fix it. src/agents/auth-profiles/external-cli-sync.ts — the readCredentials lambda needs a type guard on the "oauth" variant before the PR can safely land. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/auth-profiles/external-cli-sync.ts
Line: 78
Comment:
**Type mismatch: `ClaudeCliCredential` is not assignable to `OAuthCredential`**
`readClaudeCliCredentialsCached` returns `ClaudeCliCredential | null`, but `ExternalCliSyncProvider.readCredentials` is typed as `() => OAuthCredential | null`. `ClaudeCliCredential` is a discriminated union that includes a `{ type: "token"; token: string; expires: number; }` variant, which is structurally incompatible with `OAuthCredential` (which requires `type: "oauth"`, `access`, and `refresh`). TypeScript should reject this assignment.
At runtime, if Claude CLI ever returns a `type: "token"` credential, it would be silently pushed into `profiles` as a fake `OAuthCredential` with missing `access`/`refresh` fields, potentially breaking downstream refresh logic.
The fix is to filter only the `"oauth"` variant at the call site:
```suggestion
readCredentials: () => {
const creds = readClaudeCliCredentialsCached({ ttlMs: EXTERNAL_CLI_SYNC_TTL_MS });
return creds?.type === "oauth" ? creds : null;
},
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(auth): add Claude CLI to EXTERNAL_CL..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60725c8a61
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
+1 — hitting this on Windows 11 as well, which rules out macOS-Keychain-specific quirks. The same stale-snapshot pattern applies via the Environment
Diagnostic path matched the PR description almost verbatim
Where this shows up in doctor output In my case, Impact for Claude Max users on Windows Happy to help test the fix once it lands — I already have a stale-snapshot repro standing by on this machine. |
26fca8a to
066f343
Compare
066f343 to
e57102f
Compare
obviyus
left a comment
There was a problem hiding this comment.
Verified the Claude CLI auth-sync bug: refreshed Claude CLI OAuth credentials were readable but not registered in the external CLI sync provider list.
Maintainer follow-up: rebased onto current main, kept the provider path unified with existing external CLI sync, removed the excessive provider-normalization comment, added focused regression coverage, and resolved the outdated review threads.
Local gate: targeted auth tests plus the manual equivalent of check:changed lanes: conflict markers, core/core-test tsgo, lint:core, import cycles, auth guards, and 22 changed test files / 262 tests.
Problem
readClaudeCliCredentialsCachedalready exists and reads OAuth credentials from:Claude Code-credentialsservice)~/.claude/.credentials.json(fallback)However, it is not registered in
EXTERNAL_CLI_SYNC_PROVIDERS. This means the auth store's cached copy of the Claude CLI OAuth token goes stale when Keychain tokens rotate (~8h cycle), causing a silent fallback to paid Anthropic API keys.Symptoms
openclaw doctorreportsanthropic:claude-cliasexpiringorexpiredmodel fallback decision: candidate_failed ... reason=timeout next=anthropic-api/...primarybeing set toclaude-cli/*openclaw models auth login --provider anthropic --method clievery ~8hFix
Add a
claude-clientry toEXTERNAL_CLI_SYNC_PROVIDERS, mirroring the existingminimax-portalpattern. Uses the same 900s TTL cache.Diff
1 file changed, 7 insertions, 2 deletions.
Testing
CLAUDE_CLI_PROFILE_ID,readClaudeCliCredentialsCached, andEXTERNAL_CLI_SYNC_TTL_MSare all pre-existing exports — no new dependencies