fix(api-keys): verify revoke ownership via the user's key list#2590
Conversation
WorkOS exposes no single-key GET for user API keys — both
GET /api_keys/{id} and the user-scoped variant 404 even for existing
ids — so the DELETE route's owner check failed every revoke with
"API key not found". Replace the lookup with membership in the session
user's own key list (paginated), which is the same ownership proof:
a key enumerated under the user belongs to the user.
The actual DELETE /api_keys/{id} endpoint works and is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThe PR refactors API key deletion ownership verification. Previously, the DELETE handler re-fetched the key and compared owner IDs. Now it calls a new 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@mcpjam-inspector/server/routes/web/api-keys.ts`:
- Around line 225-252: The userOwnsApiKey helper currently returns false if the
10-page cap is hit, which can misreport owned keys as not found; instead detect
cap exhaustion and surface an internal error (or keep paging until the cursor
repeats). Modify userOwnsApiKey to (a) track the previous after cursor and stop
only if the cursor is null or unchanged, and (b) if the loop exits due to a page
cap while list_metadata.after is still present, throw an explicit error (or call
mapWorkOSError) indicating "paging limit exceeded while searching API keys"
rather than returning false; use the existing callWorkOS and list_metadata.after
handling and reference the function name userOwnsApiKey when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 83158e29-c85b-4f43-91ad-fa6202c81501
📒 Files selected for processing (1)
mcpjam-inspector/server/routes/web/api-keys.ts
Internal previewPreview URL: https://mcp-inspector-pr-2590.up.railway.app |
…ests Review feedback on #2590: if the ownership walk hits the 10-page runaway guard while list_metadata.after still points onward, ownership is unknown — returning false would read as a 404 and make keys beyond the cap silently unrevokeable. Throw INTERNAL_ERROR (and log) instead. Adds route tests with mocked WorkOS fetches: owned key revokes, foreign/ unknown id 404s without reaching DELETE, paginated match follows the after cursor, and cap exhaustion errors rather than 404s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Problem
Revoking an API key always failed with 404 "API key not found", even for the user's own keys.
The DELETE route's defense-in-depth ownership check did
GET /api_keys/{id}and comparedowner.idto the session user — but WorkOS exposes no single-key GET for user API keys. Both/api_keys/{id}and the user-scoped/user_management/users/{userId}/api_keys/{id}return 404 even for ids that exist (verified directly against WorkOS). So the check 404'd before the delete ever ran.DELETE /api_keys/{id}itself works fine.Fix
Replace the single-key lookup with
userOwnsApiKey(): walk the session user's own key list (the documented, working endpoint — same one GET / uses) and require the id to appear there. Enumeration under the user is the ownership proof, so the cross-user guarantee is unchanged: a foreign or unknown key id still reads as 404 before WorkOS sees the delete. List walk is paginated (limit 100, capped at 10 pages as a runaway guard).Follow-up to #2588.
Testing
server/tsconfig.jsontypecheck clean for the touched file;bearer-auth+web/errorsvitest suites pass (17/17).🤖 Generated with Claude Code
Note
Medium Risk
Touches authorization on API key revoke (security-sensitive), but behavior preserves cross-user 404 semantics and only fixes a broken WorkOS lookup path.
Overview
Fixes API key revoke always returning 404 for valid keys by changing how DELETE proves ownership before calling WorkOS.
The route no longer uses
GET /api_keys/{id}(WorkOS returns 404 for user keys even when they exist). It now walks the session user's/user_management/users/{userId}/api_keyslist via newuserOwnsApiKey, with pagination (limit 100, max 10 pages). Foreign or unknown ids still get 404 without DELETE; if the page cap is hit while more pages remain, the handler returns 500 so keys aren't silently treated as not owned.Adds
api-keys.test.tscovering successful revoke, foreign-key 404 without DELETE, multi-page lookup, and page-cap failure.Reviewed by Cursor Bugbot for commit 8ae7bab. Bugbot is set up for automated code reviews on this repo. Configure here.