Skip to content

fix(core): reduce OAuth refresh frequency and honor Retry-After#40

Open
iceteaSA wants to merge 4 commits into
cortexkit:mainfrom
iceteaSA:fix/oauth-refresh-429
Open

fix(core): reduce OAuth refresh frequency and honor Retry-After#40
iceteaSA wants to merge 4 commits into
cortexkit:mainfrom
iceteaSA:fix/oauth-refresh-429

Conversation

@iceteaSA
Copy link
Copy Markdown
Contributor

@iceteaSA iceteaSA commented May 22, 2026

Problem

MIN_REFRESH_BEFORE_EXPIRY_MINUTES is set to 240 (4 hours), but Claude OAuth tokens
expire in ~1 hour. This causes the background refresh timer to fire on every tick
(~30-60 requests/hour to the token endpoint), triggering 429 rate limits — especially
with multiple opencode instances running concurrently.

Additionally, 429 responses include a Retry-After header that is currently ignored.
The backoff uses a flat exponential starting at 5 minutes regardless of what the
server requests.

Fix

  1. Reduce MIN_REFRESH_BEFORE_EXPIRY_MINUTES from 240 to 15 — tokens now refresh
    at 45 minutes (with 1-hour tokens) instead of continuously. Background refresh
    fires once per token lifecycle instead of ~30-60 times.

  2. Add Retry-After header supportClaudeOAuthRefreshError now captures the
    Retry-After header from 429 responses. Supports both seconds (60) and HTTP
    date formats. buildRefreshOperationError uses it as the backoff duration when
    available, falling back to exponential backoff otherwise.

Impact

  • ~30-60x reduction in token endpoint requests per hour
  • Multiple opencode instances no longer multiply refresh pressure
  • Backoff respects server-requested delay instead of guessing

Changes

File Change
packages/core/src/accounts.ts Reduce constant, use Retry-After in backoff
packages/core/src/auth.ts Add retryAfter to ClaudeOAuthRefreshError, parse header
packages/opencode/src/index.ts Reduce main refresh constant
packages/opencode/src/tests/auth.test.ts Tests for Retry-After parsing
packages/opencode/src/tests/accounts.test.ts Tests for Retry-After backoff
packages/opencode/src/tests/index.test.ts Updated existing tests for new window

Summary by cubic

Reduce OAuth refresh frequency and honor server Retry-After on 429s to stop hammering the token endpoint. This cuts refresh requests by ~30–60x/hour and reduces rate limits across multiple instances.

  • Bug Fixes
    • Lowered the minimum refresh-before-expiry window from 4h to 15m (core and main), so 1-hour tokens refresh around 45m instead of on every tick.
    • Respect Retry-After on 429s: ClaudeOAuthRefreshError parses seconds and HTTP-date values; buildRefreshOperationError uses it for backoff, falling back to exponential when absent.
    • Updated tests to cover Retry-After parsing and backoff, and to use the new 15m window.

Written for commit 3200ef9. Summary will update on new commits. Review in cubic

iceteaSA added 4 commits May 22, 2026 19:56
MIN_REFRESH_BEFORE_EXPIRY_MINUTES was 240 (4 hours) but Claude OAuth
tokens expire in ~1 hour. This caused background refresh to fire on
every tick (~30-60 requests/hour), triggering 429 rate limits.

Reduced to 15 minutes — tokens refresh at 45 minutes instead of
immediately. Multiple opencode instances no longer multiply pressure.
ClaudeOAuthRefreshError now captures the Retry-After header from
429 responses. Supports both seconds and HTTP date formats.
Consumers can use error.retryAfter to respect the server's delay.
buildRefreshOperationError now checks ClaudeOAuthRefreshError.retryAfter
before falling back to exponential backoff. Respects server-requested
delay on 429 responses.
Tests asserting the old 4h minimum refresh window now use 10-minute
expiry tokens so they trigger within the new 15m minimum.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 6 files

Re-trigger cubic

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.

1 participant