You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: imported local CLI credential with invalid expires_at is adopted and never refreshed; ocx status shows "logged in" #1366
An imported local CLI credential (Grok ~/.grok/auth.json or Claude .credentials.json) whose expires_at is invalid (e.g. "garbage", "", "1970-01-01") is treated as valid and never refreshed:
src/oauth/local-token-detect.ts:27 — new Date(entry.expires_at as string).getTime() returns NaN for any unparseable string.
shouldAdoptGrokGeneration() (src/oauth/local-token-detect.ts:52-62) then behaves incorrectly for NaN:
disk.expires <= now + refreshSkewMs is always false for NaN → the expired/garbage credential passes the expiry gate;
bothExpiriesExist = stored.expires > 0 && disk.expires > 0 is false (NaN > 0 is false) → the function falls through to return true, so the disk credential is adopted as the authoritative generation.
authoritative() (src/oauth/index.ts:441) therefore replaces the stored credential with the garbage one, and the refresh path never re-validates it — the stale credential occupies the account slot indefinitely.
getLoginStatus() (src/oauth/index.ts:1178) reports loggedIn: !!cred (credential exists), ignoring expires/needsReauth; ocx status then prints ✓ logged in in the "OAuth logins" section for an expired or unparseable credential (the separate health block may flag needsReauth, but the logins section is the misleading first screen).
Same structural issue as a stale/epoch-garbage expires_at (e.g. 1970-01-22) observed in a real CLI credential file: the import is adopted even though it can never be refreshed.
at ~/.grok/auth.json (or a Claude .credentials.json with expiresAt: "garbage").
Run ocx login xai --import-local (or any flow that reaches detectGrokCliToken/authoritative).
Observe: the invalid-expiry credential is adopted (shouldAdoptGrokGeneration returns true); ocx status shows xai ✓ logged in; no refresh is attempted because the expiry comparison is NaN.
Expected: an unparseable/expired expires_at must be treated as unknown → refresh required (or reject the import), never as "valid and never refresh".
Version
2.11.1 (121f1ad9)
Operating system
Cross-platform (Linux/macOS CLI credential paths; Windows unaffected by ~/.grok but the same parsing logic applies)
Provider and model
xai (grok) / anthropic (claude) — local CLI token import
Checks
I searched existing issues and documentation.
I removed secrets, tokens, account details, request credentials, and personal data.
Number.isFinite guards at both parse sites (detectGrokCliToken / parseClaudeOauthPayload) → invalid/NaN expiry becomes 0 ("unknown", forces refresh validation) instead of flowing downstream as NaN.
shouldAdoptGrokGeneration explicitly refuses non-finite disk expiries.
getLoginStatus.loggedIn now also requires the active account to be not needsReauth and not expired — which automatically fixes the ocx status "OAuth logins" display via oauthLoginSummary().
Tests: 12 new (local-token-detect 9, oauth-status-privacy 3); OAuth suite 172/172 pass; tsc --noEmit clean.
Fixed by #1369 (831a120ea, merged as e8ce2b93d) and released in v2.12.0, now on npm as @bitkyc08/opencodex@2.12.0.
The released build guards expiry parsing at both call sites, so an invalid or NaNexpires_at normalizes to "unknown" and forces refresh validation instead of flowing downstream. A non-finite on-disk expiry can no longer be adopted as a valid generation, and ocx status no longer reports "logged in" for an account that needs reauthentication or has expired.
Verified in the released tree: git merge-base --is-ancestor 831a120ea 9c051342d exits 0, and git tag --contains 831a120ea includes v2.12.0.
Thanks for the precise reproduction, and thanks to @Bruce-Yii for the fix. Please reopen if you still see this on 2.12.0.
Activity
github-actions commentedon Aug 9, 2026
Automated translation bookkeeping — detected language: English.
Bruce-Yii commentedon Aug 9, 2026
Opened a fix: #1369 (base
dev).Summary of the approach:
Number.isFiniteguards at both parse sites (detectGrokCliToken/parseClaudeOauthPayload) → invalid/NaN expiry becomes0("unknown", forces refresh validation) instead of flowing downstream asNaN.shouldAdoptGrokGenerationexplicitly refuses non-finite disk expiries.getLoginStatus.loggedInnow also requires the active account to be notneedsReauthand not expired — which automatically fixes theocx status"OAuth logins" display viaoauthLoginSummary().Tests: 12 new (local-token-detect 9, oauth-status-privacy 3); OAuth suite 172/172 pass;
tsc --noEmitclean.lidge-jun commentedon Aug 10, 2026
Fixed by #1369 (
831a120ea, merged ase8ce2b93d) and released in v2.12.0, now on npm as@bitkyc08/opencodex@2.12.0.The released build guards expiry parsing at both call sites, so an invalid or
NaNexpires_atnormalizes to "unknown" and forces refresh validation instead of flowing downstream. A non-finite on-disk expiry can no longer be adopted as a valid generation, andocx statusno longer reports "logged in" for an account that needs reauthentication or has expired.Verified in the released tree:
git merge-base --is-ancestor 831a120ea 9c051342dexits 0, andgit tag --contains 831a120eaincludesv2.12.0.Thanks for the precise reproduction, and thanks to @Bruce-Yii for the fix. Please reopen if you still see this on 2.12.0.
docs(devlog): record the release and the post-release closure sweep
docs(devlog): record the release and the post-release closure sweep