Skip to content

api-key-ui-lifecycle: API keys cannot be revoked through any product route (405) — object declares revoke/restore as PATCH but disables the PATCH method #7727

Description

@huangyiirene

Symptom

There is no product route that revokes an API key.

  • Observed:PATCH /api/v1/data/sys_api_key/{id} {revoked:true} (as admin) → 405OBJECT_API_METHOD_NOT_ALLOWED, allowed:[get,list,aggregate,history,export]. Same 405 for {revoked:false} (restore). Reproduced 3×, including through the real UI: Setup → API Keys → Open menu → Revoke API Key → Continue produces an error toast, the key keeps authenticating, and the row still reads revoked=false.
  • Expected: 200, and the key stops authenticating.

No alternative route exists — route-ledger.ts carries only POST /keys; /api/v1/auth/api-key/* and DELETE /api/v1/keys/{id} all 404.

Root cause

packages/platform-objects/src/identity/sys-api-key.object.tscontradicts itself:

So the two halves cancel out: the declared action fires a PATCH the object refuses at the method gate. Enforcement of the flag is fine — setting revoked=1 out-of-band makes the very next x-api-key call 401 UNAUTHENTICATED — so the missing piece is purely the write path. Fix is either to allow update scoped to the revoked column, or to give revoke/restore a dedicated auth route.

Route: domain:metadata (the contradiction lives entirely in the platform-objects object definition — both the action declarations and the apiMethods gate are there). If the maintainer instead chooses the dedicated-auth-route fix, the work moves to a route and would be domain:cli — but as located the defect and its fix sit in the platform object, so domain:metadata.

Security consequence

⚠️A leaked API key cannot be revoked without direct database access. The QA run filed this publicly deliberately: it is a dead feature rather than a bypassable gate — knowing about it grants an attacker nothing they don't already have. Adding security for triage visibility.

Nothing pins this today: the unit tests (http-dispatcher.keys.test.ts, resolve-execution-context.test.ts) exercise key resolution with a pre-revoked row and never call the PATCH route the action declares.

Reproduction

  1. POST /api/v1/keys {name} → 201.
  2. PATCH /api/v1/data/sys_api_key/{id} {revoked:true} as admin → 405OBJECT_API_METHOD_NOT_ALLOWED.
  3. The key still authenticates; revoked still reads false. Same via the Setup → API Keys → Revoke UI (error toast).

Source

Extracted from the QA run #7663 (framework 92f26f7, console 09987b680).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions