Skip to content

fix: answer retried rejected credentials without re-validating them - #52

Closed
fatwang2 wants to merge 1 commit into
mainfrom
fix/cache-rejected-credentials
Closed

fatwang2 wants to merge 1 commit into
mainfrom
fix/cache-rejected-credentials

Conversation

@fatwang2

Copy link
Copy Markdown
Member

Requested by fatwang2

Why

The API's error count tripled on 2026-10-23 (Beijing time). About 10.7k of the 31.4k errors were GET /usage 401s from the MCP host: validateCredential calls /usage on every MCP exchange. Current container logs show one client (userAgent: copilot-cli) sending ping with a rejected credential every six seconds. It ignores the invalid_token challenge and never reauthorizes. Each ping cost an API call that was recorded as a 401, and it is still going.

What

  • rememberRejections() wraps the credential validator in createHttpApp. A definite rejection (null) is remembered for 60 seconds, keyed by the credential's SHA-256 digest, with at most 1,000 entries (the oldest is evicted first). A repeat within that window gets the same 401 invalid_token challenge without calling /usage.
  • Validator exceptions (the 503 outage path) are not remembered.
  • The 60-second TTL matches the gateway's own rejected-credential cache. The gateway reports a Clerk outage as unauthenticated, so the TTL bounds how long a valid OAuth token could stay locked out after one.

For the six-second pinger this cuts /usage calls from about 600 to about 60 per hour.

Tests

  • New: three retries of a rejected credential validate once and all get invalid_token, while two outage responses validate twice.
  • New: a rejection expires after 60 seconds, and an accepted credential is never cached.
  • npm test: 49/49 pass.

🤖 Generated with Claude Code

A client that ignores the invalid_token challenge keeps presenting the same
credential, and every retry became a GET /usage the API records as a 401. On
2026-10-23 one copilot-cli install pinged every six seconds with a rejected
token: about 10.7k 401s, a third of the API's errors that day.

Remember a definite rejection for 60 seconds, keyed by the credential's
SHA-256. Validation failures (503) are not remembered, and the short TTL
bounds how long a valid OAuth token stays locked out if Clerk briefly reports
it as unauthenticated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fatwang2 fatwang2 self-assigned this Oct 24, 2026

Copy link
Copy Markdown
Member Author

Closing as a duplicate of #51, which makes the same change (60s cache of rejected credentials keyed by SHA-256, outages not cached). #51 is green and mergeable.


Generated by Claude Code

@fatwang2 fatwang2 closed this Oct 24, 2026
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