Skip to content

Usage endpoint should trigger auth banner when Claude OAuth token is expired#455

Merged
jonwiggins merged 1 commit into
mainfrom
optio/task-00104eb8-8d36-4506-96a4-62cf171597a6
Apr 20, 2026
Merged

Usage endpoint should trigger auth banner when Claude OAuth token is expired#455
jonwiggins merged 1 commit into
mainfrom
optio/task-00104eb8-8d36-4506-96a4-62cf171597a6

Conversation

@jonwiggins

Copy link
Copy Markdown
Owner

Closes #454

What changed

When getClaudeUsage() in auth-service.ts receives a 401 or 403 from Anthropic's usage API (https://api.anthropic.com/api/oauth/usage), it now:

  1. Records an auth event via recordAuthEvent('claude', ..., 'usage-endpoint') so the failure is visible to getRecentAuthFailures() and surfaces in /api/auth/usage's authFailures.claude flag.
  2. Publishes a WebSocket auth:failed event so connected clients trigger the GlobalAuthBanner immediately — without waiting for the next 5-minute /api/auth/status poll or a task launch failure.
  3. Invalidates the usage cache so subsequent calls don't return stale "healthy" data.

This brings the usage endpoint path in line with the agent-output path (task-worker.ts) and the proactive-probe path (token-validation-worker.ts), both of which already publish auth:failed events.

Both recordAuthEvent and publishEvent are wrapped in try/catch so failures in these side-effects don't break the usage response itself.

How to test

  1. Set a deliberately invalid or expired CLAUDE_CODE_OAUTH_TOKEN in secrets
  2. Open any page that calls /api/auth/usage (e.g., the dashboard)
  3. The "Claude OAuth token expired" banner should appear within seconds
  4. Run npx vitest run apps/api/src/services/auth-service.test.ts — all 6 tests pass, covering:
    • 401 triggers recordAuthEvent + publishEvent
    • 403 triggers recordAuthEvent + publishEvent
    • 500 does not trigger auth failure handling
    • Errors in recordAuthEvent or publishEvent don't break the response
    • Successful usage calls are cached correctly

…th token

When getClaudeUsage() receives a 401 or 403 from Anthropic's usage API,
it now records an auth event and publishes an auth:failed WebSocket event
so the UI shows the re-auth banner immediately — without waiting for the
next 5-minute /api/auth/status poll or a task launch failure.

Closes #454

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jonwiggins jonwiggins merged commit 7c74723 into main Apr 20, 2026
7 checks passed
jplorier pushed a commit to jplorier/optio that referenced this pull request May 5, 2026
…th token (jonwiggins#455)

When getClaudeUsage() receives a 401 or 403 from Anthropic's usage API,
it now records an auth event and publishes an auth:failed WebSocket event
so the UI shows the re-auth banner immediately — without waiting for the
next 5-minute /api/auth/status poll or a task launch failure.

Closes jonwiggins#454

Co-authored-by: Optio Agent <optio-agent@noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Usage endpoint should trigger auth banner when Claude OAuth token is expired

1 participant