Claude OAuth source uses the stale ~/.claude/.credentials.json file instead of the live Keychain token
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 68/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- macos, swift
- Domain
- authentication, desktop
Research direction
Start by tracing the Claude OAuth API credential-loading path used when “Allow reading Claude Code's credentials” is enabled, comparing the on-disk ~/.claude/.credentials.json source with the macOS Keychain item named Claude Code-credentials. Reproduce the expired-file state and verify that Refresh uses the live Keychain token, with Session and Weekly usage no longer dropping to 0%.
Written by the indexing model from the issue text.
Description
Summary
With Usage source: OAuth API and Allow reading Claude Code's credentials enabled, CodexBar reads the Claude OAuth token from the on-disk ~/.claude/.credentials.json file. That file's access token expires roughly every 8h and isn't kept fresh, so once it lapses the menu shows a hard error and Session/Weekly usage drops to 0% — even though the live Keychain item Claude Code-credentials still holds a valid, unexpired token the whole time.
Cost/token totals keep working (those come from local logs); only the plan-usage bars break.
Observed on CodexBar 0.56.3 (build 134), macOS 15.6, Claude Code 2.1.258, Team plan.
What I see
Menu card:
Claude OAuth token expired and delegated Claude CLI refresh failed: Claude CLI session exited.. Run
claude login, then retry.
Session shows 0%. On 0.56.2 the same state showed:
Claude OAuth token expired and delegated refresh is cooling down. Please retry shortly, or run
claude login.
The suggested claude login is a red herring — Claude Code is fully signed in and its Keychain token is valid.
Why it happens
On macOS, Claude Code keeps its live token in the login Keychain (Claude Code-credentials) and refreshes it there. The ~/.claude/.credentials.json file is a secondary copy that goes stale. CodexBar reads (and fingerprints) that file. At one moment while the error was showing:
- File
expiresAt: in the past —2026-09-02T18:55Z - Keychain
expiresAt: in the future —2026-09-03T02:50Z, with a recentmdat
When the file token is expired, CodexBar falls back to a delegated Claude CLI refresh, which exits without producing a token → the error above. It never reads the fresh Keychain value, despite "Allow reading Claude Code's credentials" being on and Keychain prompt policy set to "Always allow prompts" (no Keychain prompt ever appears).
Steps to reproduce
- Usage source = OAuth API, "Allow reading Claude Code's credentials" on.
- Let the OAuth access token in
~/.claude/.credentials.jsonexpire (~8h; the Keychain token stays fresh through normal Claude Code use). - Open the menu / hit Refresh.
Result: "OAuth token expired … Claude CLI refresh failed", Session 0%.
Workaround
Copying the current Keychain token into the file fixes it instantly (until that copy expires ~8h later):
security find-generic-password -s "Claude Code-credentials" -w > ~/.claude/.credentials.json
Expected
In OAuth-API mode with Keychain reading enabled, CodexBar should treat the live Keychain item as the source of truth (it stays fresh on its own), or at minimum refresh the on-disk file from the Keychain before falling back to the CLI. As it stands, a valid, readable token is sitting in the Keychain and CodexBar doesn't use it.
Possibly related: #3287, #3249.
- Dominant language
- Swift
- Stars
- 21.6k
- Forks
- 2k
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 385
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from steipete/CodexBar
-
clawsweeper:needs-live-repro clawsweeper:needs-maintainer-review clawsweeper:no-new-fix-pr impact:ux-friction issue-rating: 🐚 platinum hermit P2
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
clawsweeper:needs-maintainer-review clawsweeper:needs-product-decision clawsweeper:no-new-fix-pr clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster P2
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
clawsweeper:needs-maintainer-review clawsweeper:needs-product-decision clawsweeper:no-new-fix-pr impact:ux-friction issue-rating: 🌊 off-meta tidepool P3
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
clawsweeper:needs-maintainer-review clawsweeper:needs-product-decision clawsweeper:needs-security-review clawsweeper:no-new-fix-pr impact:auth-provider impact:security issue-rating: 🌊 off-meta tidepool P2
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
impact:ux-friction issue-rating: 🦪 silver shellfish P2
Difficulty 3/5 1-2 days Newbie friendliness 65/100
All issues in steipete/CodexBar
Similar issues
-
tvOS
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
skiptools/skip-fuse-ui#147 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
OneBusAway/onebusaway-ios#1438 · 1 reaction ·