openclaw - ✅(Solved) Fix Local oauth profile (`anthropic:claude-cli`) becomes stale and never auto-resyncs from external CLI credentials [2 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#80129Fetched 2026-05-11 03:18:27
View on GitHub
Comments
2
Participants
3
Timeline
16
Reactions
2
Timeline (top)
referenced ×11commented ×2cross-referenced ×2closed ×1

OpenClaw maintains a local oauth profile per provider in ~/.openclaw/agents/<agent>/agent/auth-profiles.json. For oauth profiles that bootstrap from an external CLI (e.g. anthropic:claude-cli derives from Claude CLI's ~/.claude/.credentials.json), the local profile is set once at onboard but never auto-refreshes when the source CLI's oauth refreshes.

This causes:

  1. Local profile's expires field to fall into the past after the source CLI auto-refreshes (typically 1-2 days)
  2. resolveExternalCliAuthProfiles() in dist/store-DL6VwwSr.js:686 (in OpenClaw 2026.5.6) to log a DEBUG message every poll: "used external cli oauth bootstrap because local oauth was missing or unusable"
  3. The DEBUG line fires once per auth-resolution event (per agent invocation / per LLM call / per tool call) — high-volume log flood

The system itself continues to function correctly — the bootstrap-fallback succeeds — but the log channel is flooded with what is functionally a non-failure.

Root Cause

  1. Local profile's expires field to fall into the past after the source CLI auto-refreshes (typically 1-2 days)
  2. resolveExternalCliAuthProfiles() in dist/store-DL6VwwSr.js:686 (in OpenClaw 2026.5.6) to log a DEBUG message every poll: "used external cli oauth bootstrap because local oauth was missing or unusable"
  3. The DEBUG line fires once per auth-resolution event (per agent invocation / per LLM call / per tool call) — high-volume log flood

Fix Action

Fix / Workaround

Manual workaround

PR fix notes

PR #80148: fix(auth): persist fresh external-cli credential back to local store when stored profile is expired

Description (problem / solution / changelog)

When a non-bootstrapOnly provider (e.g. anthropic:claude-cli) has a stale local profile but the external CLI holds a fresh token, the bootstrap path fires on every auth-resolution call and floods the log with repeated DEBUG messages.

Write the fresh credential back to auth-profiles.json (fire-and-forget) so subsequent calls find a valid local profile and the bootstrap-fallback stops recurring.

Fixes #80129

Changes

  • src/agents/auth-profiles/external-auth.ts: after resolving a fresh token from the external CLI, persist it back to the local store via a lazy-loaded upsertAuthProfileWithLock call (dynamic import avoids a static cycle: store → external-auth → upsert-with-lock → store)
  • src/agents/auth-profiles/external-oauth.test.ts: tests cover persist-on-stale and no-persist-when-current paths

Real behavior proof

  • Behavior or issue addressed: When the local anthropic:claude-cli profile is stale, each auth-resolution call triggers the external-CLI bootstrap fallback and floods the gateway log with repeated DEBUG bursts. After this patch the fresh token is written back so the next call finds it in the local store.
  • Real environment tested: Local OpenClaw Gateway 2026.5.10, Node v24, macOS, anthropic:claude-cli configured as non-bootstrapOnly provider.
  • Exact steps or command run after this patch:
    1. Let the local anthropic:claude-cli profile expire (set expires to a past timestamp in auth-profiles.json).
    2. Run openclaw agent --message "ping".
    3. Run a second openclaw agent --message "ping" immediately after.
    4. Inspect gateway debug logs for bootstrap-fallback messages.
  • Evidence after fix: Redacted runtime log from gateway debug output after applying the patch:
    [debug] external-cli: resolved fresh token for anthropic:claude-cli, persisting back to auth-profiles.json
    First request: bootstrap fires once, token persisted. Second request: no bootstrap DEBUG burst — profile resolved from local store. Before this patch: every request emitted a repeated bootstrap DEBUG burst regardless of how many times the same token had been resolved.
  • Observed result after fix: The bootstrap fallback fires once per expiry cycle instead of on every request. Subsequent calls resolve the profile from the local store without triggering the fallback.
  • What was not tested: Multi-profile configurations; Windows paths; profiles with bootstrapOnly: true (unaffected by the !providerConfig.bootstrapOnly guard).

Changed files

  • src/agents/auth-profiles/external-auth.ts (modified, +35/-0)
  • src/agents/auth-profiles/external-cli-sync.ts (modified, +4/-0)
  • src/agents/auth-profiles/external-oauth.test.ts (modified, +66/-1)

PR #80274: [codex] Persist external CLI OAuth refreshes

Description (problem / solution / changelog)

Summary

  • persist fresher managed external CLI OAuth credentials, such as anthropic:claude-cli, back into the owning auth-profiles.json store
  • keep bootstrap-only Codex CLI credentials runtime-only so local Codex refresh tokens remain canonical
  • skip external CLI rereads when a managed local OAuth profile is already usable, preventing steady-state debug log churn

Fixes #80129.

Verification

  • pnpm test src/agents/auth-profiles.external-cli-sync.test.ts src/agents/auth-profiles.store-cache.test.ts src/agents/auth-profiles.store.save.test.ts
  • OPENCLAW_TESTBOX=0 pnpm check:changed

Real behavior proof

Behavior or issue addressed: A stale persisted anthropic:claude-cli OAuth profile should resync from fresher Claude CLI credentials and write the refreshed credential back to auth-profiles.json.

Real environment tested: Local OpenClaw checkout on macOS, isolated temporary HOME, isolated temporary agent directory, actual loadAuthProfileStoreForRuntime() path, actual Claude CLI credential-file reader, keychain disabled, no mocks. Tokens below are synthetic and redacted.

Exact steps or command run after this patch: Ran pnpm exec tsx with a local proof script that created a stale auth-profiles.json, created a fresh .claude/.credentials.json, then loaded the auth store through loadAuthProfileStoreForRuntime(agentDir, { allowKeychainPrompt: false, externalCliProfileIds: ["anthropic:claude-cli"] }).

Evidence after fix:

Real OpenClaw auth-store proof for #80129
environment: isolated temp HOME plus Claude CLI credential file; no keychain; no mocks
command: pnpm exec tsx local proof script using loadAuthProfileStoreForRuntime()
before persisted profile: provider=claude-cli, access=redacted-stale-access-token, expired=true
external Claude CLI credential: access=redacted-fresh-access-token, expiresInMs=86400000
after persisted profile: provider=claude-cli, access=redacted-fresh-access-token, expiresAdvanced=true
runtime profile matches persisted refresh: true
auth-profiles.json updated on disk: true

Observed result after fix: The stale persisted Claude CLI profile was replaced on disk with the fresh external Claude CLI credential, and the runtime profile matched the newly persisted access and refresh tokens.

What was not tested: No live Anthropic API call and no multi-day natural OAuth rollover; the proof exercises the real local OpenClaw/Claude CLI credential sync path with synthetic redacted credentials.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/clickclack/src/inbound.test.ts (modified, +13/-1)
  • extensions/codex/src/app-server/run-attempt.context-engine.test.ts (modified, +4/-3)
  • extensions/diffs/src/browser.test.ts (modified, +1/-1)
  • extensions/discord/src/monitor/provider.test.ts (modified, +3/-1)
  • extensions/googlechat/src/channel.test.ts (modified, +11/-2)
  • extensions/irc/src/inbound.behavior.test.ts (modified, +4/-2)
  • extensions/line/src/bot-handlers.test.ts (modified, +2/-2)
  • extensions/line/src/setup-surface.test.ts (modified, +3/-1)
  • extensions/lmstudio/src/models.test.ts (modified, +1/-1)
  • extensions/memory-core/src/dreaming-phases.test.ts (modified, +1/-1)
  • extensions/memory-core/src/dreaming.test.ts (modified, +1/-1)
  • extensions/nextcloud-talk/src/inbound.behavior.test.ts (modified, +3/-1)
  • extensions/nextcloud-talk/src/send.cfg-threading.test.ts (modified, +1/-1)
  • extensions/qqbot/src/bridge/tools/remind.test.ts (modified, +2/-2)
  • extensions/qqbot/src/engine/commands/slash-commands-impl.test.ts (modified, +2/-4)
  • extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts (modified, +1/-1)
  • extensions/searxng/src/searxng-client.test.ts (modified, +11/-5)
  • extensions/slack/src/monitor/media.test.ts (modified, +1/-1)
  • extensions/synology-chat/src/channel.test.ts (modified, +1/-1)
  • extensions/tavily/src/tavily-tools.test.ts (modified, +9/-2)
  • extensions/telegram/src/webhook.test.ts (modified, +3/-1)
  • src/agents/auth-profiles.external-cli-sync.test.ts (modified, +42/-3)
  • src/agents/auth-profiles.store-cache.test.ts (modified, +267/-2)
  • src/agents/auth-profiles.store.save.test.ts (modified, +1/-0)
  • src/agents/auth-profiles/external-auth.ts (modified, +51/-1)
  • src/agents/auth-profiles/external-cli-sync.ts (modified, +16/-6)
  • src/agents/auth-profiles/store.ts (modified, +163/-8)
  • src/agents/harness/v2.test.ts (modified, +8/-8)
  • src/agents/tools/video-generate-tool.test.ts (modified, +19/-15)
  • src/cli/daemon-cli/restart-health.test.ts (modified, +1/-1)
  • src/commands/auth-choice.test.ts (modified, +5/-2)
  • src/flows/channel-setup.test.ts (modified, +1/-1)
  • src/gateway/server-methods/skills-upload.test.ts (modified, +1/-1)
  • src/gateway/server-startup-config.secrets.test.ts (modified, +1/-1)
  • src/gateway/server-startup-plugins.test.ts (modified, +1/-1)
  • src/gateway/server.sessions.reset-hooks.test.ts (modified, +2/-2)
  • src/gateway/tools-invoke-http.test.ts (modified, +1/-1)
  • src/infra/outbound/delivery-queue.recovery.test.ts (modified, +6/-2)
  • src/wizard/setup.finalize.test.ts (modified, +15/-12)
RAW_BUFFERClick to expand / collapse

Summary

OpenClaw maintains a local oauth profile per provider in ~/.openclaw/agents/<agent>/agent/auth-profiles.json. For oauth profiles that bootstrap from an external CLI (e.g. anthropic:claude-cli derives from Claude CLI's ~/.claude/.credentials.json), the local profile is set once at onboard but never auto-refreshes when the source CLI's oauth refreshes.

This causes:

  1. Local profile's expires field to fall into the past after the source CLI auto-refreshes (typically 1-2 days)
  2. resolveExternalCliAuthProfiles() in dist/store-DL6VwwSr.js:686 (in OpenClaw 2026.5.6) to log a DEBUG message every poll: "used external cli oauth bootstrap because local oauth was missing or unusable"
  3. The DEBUG line fires once per auth-resolution event (per agent invocation / per LLM call / per tool call) — high-volume log flood

The system itself continues to function correctly — the bootstrap-fallback succeeds — but the log channel is flooded with what is functionally a non-failure.

Reproduction

  1. Install OpenClaw with Claude CLI as one of the auth-providers (openclaw onboard with anthropic-cli choice)
  2. Wait 1-2 days for the source Claude CLI's oauth to auto-refresh
  3. Inspect ~/.openclaw/agents/main/agent/auth-profiles.jsonprofiles["anthropic:claude-cli"].expires — observe it is in the past
  4. Inspect ~/.claude/.credentials.jsonclaudeAiOauth.expiresAt — observe it is in the future
  5. Tail OpenClaw gateway log at debug-level (logging.level: debug or lower); observe DEBUG-level flood of bootstrap messages

Observed impact (production deployment, 2026-05-09)

  • 3,490 instances of the bootstrap-flood DEBUG line in a single gateway-log retention window
  • All 3,490 from a single profile (anthropic:claude-cli); zero instances from openai-codex (which has bootstrapOnly: true) or minimax-portal
  • No functional failure — bootstrap-fallback succeeds, system works correctly. Pure log-noise but high-volume enough to mask other diagnostic signals.

Manual workaround

Copy fresh oauth values from the source CLI credentials into OpenClaw's local profile, with field-name translation:

External CLI key (Claude CLI)OpenClaw local-profile key
accessTokenaccess
refreshTokenrefresh
expiresAtexpires

Backup auth-profiles.json first; no gateway-restart strictly required (next resolveExternalCliAuthProfiles() poll reads the file). Manual fix recurs every 1-2 days as the source CLI refreshes its own oauth.

Note: openclaw onboard --auth-choice anthropic-cli --non-interactive --accept-risk does NOT refresh just the profile — it also rewrites agents.defaults.agentRuntime.id and agents.defaults.model.primary, which is unexpected for what looks like a profile-refresh subcommand. So onboard is not the right tool for refreshing a single existing oauth profile in 5.6.

Suggested fix

Option A (preferred): when resolveExternalCliAuthProfiles() detects external-CLI oauth is fresher than the local profile, write the external values into the local profile (with field-translation) before continuing. Single-place fix; eliminates the flood at source.

Option B: add a periodic background task (e.g. once per hour) that resyncs all local oauth profiles whose external-CLI source has fresher credentials. Less surgical; broader scope.

Option C (least preferred): change the DEBUG-level log$1.debug(...) to fire only on state-change rather than per-poll. Reduces log-noise but doesn't fix the underlying staleness — local profile's expires would still be in the past.

Severity

Low — not a functional bug; pure log-noise. But the per-poll firing makes it surface in any non-trivial deployment, masks other diagnostic signals, and creates an ongoing manual-maintenance burden for users who run with debug-level logging.

Environment

  • OpenClaw 2026.5.6 (regression #76562 still active in this version)
  • Windows 11 Pro 26200
  • Claude CLI as external auth provider (anthropic:claude-cli profile)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Local oauth profile (`anthropic:claude-cli`) becomes stale and never auto-resyncs from external CLI credentials [2 pull requests, 2 comments, 3 participants]