Skip to content

fix(auth): key management requires the admin scope the docs already promised - #7

Closed
Oliver-CG wants to merge 2 commits into
Miosa-osa:mainfrom
Oliver-CG:upstream/admin-scope-gate
Closed

Oliver-CG wants to merge 2 commits into
Miosa-osa:mainfrom
Oliver-CG:upstream/admin-scope-gate

Conversation

@Oliver-CG

Copy link
Copy Markdown
Contributor

What

The comment block above the key-management routes states: "When auth is on (auth_required: true) they require the admin scope." Nothing enforces that — scopes is stored on every key and read nowhere in the request path (only workspace_scope is checked, by WorkspaceAuthPlug).

Consequence: any authenticated key, however narrowly scoped, can POST /api/auth/keys and mint itself a "*" key — least-privilege issuance is decoration.

Change

POST/GET /api/auth/keys, POST .../revoke and DELETE .../:id now require "admin" or "*" in the calling key's scopes → 403 admin_scope_required otherwise. Anonymous dev mode (auth off) is unchanged, same as every other route.

Regression tests included (read-scoped key: 403 on all four; wildcard key: 201).

🤖 Generated with Claude Code

…romised

The section comment above /api/auth/keys says the routes 'require the admin
scope' when auth is on; nothing enforced it — scopes were stored on every key
and read nowhere. Any workspace-scoped key could mint itself a '*' key. Mint,
list, revoke and delete now demand 'admin' or '*' in the calling key's
scopes; anonymous dev mode is unchanged.

(cherry picked from commit 41110d9)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@robertohluna

Copy link
Copy Markdown
Contributor

Thanks for this. The escalation path is already closed on main: since 8b0e262 (2026-09-08) PermissionPlug requires the admin scope for every /api/auth/keys route, covered by test/api/control_plane_integrity_test.exs (a scoped key minting a * key gets 403 permission_scope_denied). After updating this branch to main, the new test fails only because PermissionPlug rejects first with that code, so the router-level checks here are redundant. Closing as superseded.

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.

2 participants