Skip to content

fix: preserve Codex usage when token refresh fails - #386

Merged
xiufengsun merged 1 commit into
xiufengsun:mainfrom
LinYYY:codex/fix-codex-remaining-usage
Jul 28, 2026
Merged

fix: preserve Codex usage when token refresh fails#386
xiufengsun merged 1 commit into
xiufengsun:mainfrom
LinYYY:codex/fix-codex-remaining-usage

Conversation

@LinYYY

@LinYYY LinYYY commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • align proactive Codex token refresh with the official CLI by using JWT expiry and a five-minute refresh window, with the existing eight-day fallback for opaque tokens
  • preserve confirmed live Codex quota data when refresh-token renewal returns 401 but the current access token is still valid
  • remove the legacy refresh scope and provide clearer messages for expired, reused, or invalidated refresh tokens
  • add regression coverage for refresh timing and the refresh-401/live-usage-200 path

Testing

  • node --test test/codex-token-refresh.test.js test/usage-limits.test.js — 117 passed
  • npm run validate:guardrails
  • macOS Release App and DMG built and signature/checksum verified
  • installed App returned live Codex Pro weekly quota with HTTP 200 and no token-file mutation

Summary by CodeRabbit

  • Improvements

    • Codex access tokens now refresh shortly before JWT expiration, with legacy-token fallback support.
    • Usage data remains available when an existing access token is still valid, even if token refresh fails.
    • Upstream authorization statuses are preserved for unavailable usage data.
    • Successful live usage responses now include consistent cache and freshness information.
  • Bug Fixes

    • Added clearer re-authentication messages for expired, reused, or invalidated refresh tokens.
    • Improved handling of cached usage data when live requests fail.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Codex token refresh now uses JWT expiry windows, provides specific refresh-token errors, preserves upstream usage status, and conditionally requires re-authentication based on live usage results. Cache handling and tests were updated accordingly.

Changes

Codex refresh and usage flow

Layer / File(s) Summary
JWT-aware token refresh
src/lib/codex-token-refresh.js
Token refresh uses JWT exp with a five-minute window, falls back for legacy tokens, omits scope, and maps OpenAI refresh error codes to structured messages.
Usage fetch and fallback flow
src/lib/usage-limits.js
Usage responses preserve upstream 401/403/404 status; live results update the disk cache, while expired refresh tokens require re-authentication only when live usage does not succeed.
Refresh and usage behavior tests
test/codex-token-refresh.test.js, test/usage-limits.test.js
Tests cover JWT refresh boundaries, request payloads, refresh-token error handling, re-authentication, and valid access tokens after refresh failure.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UsageAggregator
  participant TokenRefresh
  participant WHAMUsage
  participant DiskCache
  UsageAggregator->>TokenRefresh: Check JWT-aware staleness
  TokenRefresh-->>UsageAggregator: Refreshed tokens or refresh error
  UsageAggregator->>WHAMUsage: Fetch usage with access token
  WHAMUsage-->>UsageAggregator: Live usage and upstream status
  UsageAggregator->>DiskCache: Write fresh data or read prior snapshot
Loading

Suggested reviewers: mm7894215, xiufengsun

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: preserving Codex usage even when token refresh fails.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/codex-token-refresh.js (1)

58-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing test for the refresh_token_invalidated message branch.

The refresh_token_expired and refresh_token_reused branches now have dedicated tests, but refresh_token_invalidated (line 78-80) has no equivalent coverage in test/codex-token-refresh.test.js, despite being explicitly called out in the PR objectives ("improves messages for expired, reused, or invalidated refresh tokens").

✅ Suggested test addition
it("explains a refresh_token_invalidated 401 separately", async () => {
  await assert.rejects(
    refreshCodexTokens({
      refreshToken: "rt-abc",
      fetchImpl: async () => ({
        ok: false,
        status: 401,
        json: async () => ({ error: { code: "refresh_token_invalidated" } }),
      }),
    }),
    (err) => {
      assert.equal(err.code, "REFRESH_TOKEN_EXPIRED");
      assert.equal(err.openaiErrorCode, "refresh_token_invalidated");
      assert.match(err.message, /revoked/);
      return true;
    },
  );
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/codex-token-refresh.js` around lines 58 - 85, Add a dedicated test in
the refreshCodexTokens test suite for a 401 response containing error code
refresh_token_invalidated. Assert the rejected error preserves
REFRESH_TOKEN_EXPIRED and openaiErrorCode, and that its message describes the
token as revoked.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/codex-token-refresh.js`:
- Around line 58-85: Add a dedicated test in the refreshCodexTokens test suite
for a 401 response containing error code refresh_token_invalidated. Assert the
rejected error preserves REFRESH_TOKEN_EXPIRED and openaiErrorCode, and that its
message describes the token as revoked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6109beb5-9a0d-40b2-af0b-a96d015e1dd8

📥 Commits

Reviewing files that changed from the base of the PR and between 11588c5 and 063d410.

📒 Files selected for processing (4)
  • src/lib/codex-token-refresh.js
  • src/lib/usage-limits.js
  • test/codex-token-refresh.test.js
  • test/usage-limits.test.js

@xiufengsun
xiufengsun merged commit 7f7507b into xiufengsun:main Jul 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants