Skip to content

fix: prevent Cloudflare challenge from blocking usage refresh#89

Open
Js2Hou wants to merge 2 commits into
Lampese:mainfrom
Js2Hou:fix/cloudflare-challenge-blocks-usage-refresh
Open

fix: prevent Cloudflare challenge from blocking usage refresh#89
Js2Hou wants to merge 2 commits into
Lampese:mainfrom
Js2Hou:fix/cloudflare-challenge-blocks-usage-refresh

Conversation

@Js2Hou

@Js2Hou Js2Hou commented Jun 27, 2026

Copy link
Copy Markdown

When codex is running, the accounts/check endpoint (chatgpt.com/backend-api/accounts/check/v4-2023-04-27) may be intercepted by Cloudflare's managed challenge (403), causing the entire usage refresh to fail before get_usage (wham/usage) ever executes.

Changes:

  • Backend: detect Cloudflare challenge response and return a readable error instead of dumping the challenge HTML page
  • Frontend: wrap metadata refresh in try/catch so that plan-type / subscription fetch failures never block the core usage (rate-limit / credits) refresh

Js2Hou added 2 commits June 28, 2026 08:16
When codex is running, the accounts/check endpoint
(chatgpt.com/backend-api/accounts/check/v4-2023-04-27) may be
intercepted by Cloudflare's managed challenge (403), causing
the entire usage refresh to fail before get_usage (wham/usage)
ever executes.

Changes:
- Backend: detect Cloudflare challenge response and return
  a readable error instead of dumping the challenge HTML page
- Frontend: wrap metadata refresh in try/catch so that
  plan-type / subscription fetch failures never block the
  core usage (rate-limit / credits) refresh
@Js2Hou
Js2Hou force-pushed the fix/cloudflare-challenge-blocks-usage-refresh branch from e63fec2 to 588e3c0 Compare June 28, 2026 00:21

@emreertunc emreertunc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the fix. The usage-refresh direction looks good overall, but I found two issues that should be fixed before approval:

  1. cargo fmt --manifest-path src-tauri/Cargo.toml -- --check fails on src-tauri/src/api/usage.rs. The new anyhow::bail! call needs to be formatted as rustfmt expects.

  2. The README now documents a Windows portable asset named codex-switcher.exe, but the current Lampese release assets do not include that file. The existing release naming/versioning scheme should not be changed or broken. Please either remove the portable EXE docs for now, or add a portable asset in a way that keeps the current installer/MSI asset names and versioned release artifacts intact.

I ran pnpm build, cargo test --manifest-path src-tauri/Cargo.toml, and git diff --check; those passed.

@Jeakcey

Jeakcey commented Jul 11, 2026

Copy link
Copy Markdown

Confirmed real-world reproduction: renewed subscription still shown as expired

I reproduced this on Windows with Codex Switcher v0.2.7. The affected ChatGPT OAuth account was not active in Codex at the time, but its stored OAuth token had refreshed, so inactivity does not appear to be the cause.

Observed with the same account credentials:

  • GET /backend-api/accounts/check/v4-2023-04-27 returned 403, text/html, with a Cloudflare managed challenge.
  • GET /backend-api/wham/usage returned 200, application/json, with current plan/rate-limit data.
  • A newly issued ID token still carried the previous chatgpt_subscription_active_until value and an older chatgpt_subscription_last_checked.
  • Adding browser-like User-Agent, Accept, Origin, Referer, and Sec-Fetch-* headers without browser cookies did not change the 403.

This creates a confusing split: usage bars are current while the account card continues to render a persisted past date as authoritative Expired. It also explains why a normal token refresh or switching to that account does not reliably repair the date.

PR #89 is useful for keeping usage refresh working, but it does not address the misleading expiry state. Suggested follow-ups:

  1. Track expiry provenance and freshness, for example subscription_expires_at_source and subscription_expires_at_checked_at, instead of treating a stored/token date as indefinitely authoritative.
  2. If a past expiry cannot be live-revalidated, render Expiry unavailable or Last verified ... rather than a red Expired.
  3. Keep metadata failures non-blocking so /wham/usage always refreshes independently.
  4. Do not overwrite a last-known-good expiry with None when the response lacks entitlement.expires_at; retain it as stale and expose the validation failure separately.
  5. Consider a manual expiry override/sync fallback, because the supported Codex account and usage data does not currently expose billing expiry.
  6. Fix the related Last updated: Never state: AccountCard initializes local lastRefresh before async usage arrives and only updates it after a fully successful card-level refresh. A backend fetched_at value, or updating the state when valid usage arrives, would be more accurate.

Useful regression cases:

  • Renewed account + stale ID-token expiry + metadata 403 => stale/unavailable, not authoritative expired.
  • Metadata 403 => usage still refreshes successfully.
  • Metadata 200 with entitlement.expires_at => persist and display the new date immediately.
  • Async usage success after mount => Last updated no longer remains Never.

No account identifiers or tokens are included in this report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants