Add OAuth client list and revoke endpoints

Superuser-only management for agents that registered themselves: list them
with whether anyone approved them, and withdraw one without rotating the
signing key and cutting off every other agent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A
This commit is contained in:
2026-08-16 16:29:47 +02:00
co-authored by Claude Fable 5
parent 19970b0ad8
commit f239c884b6
5 changed files with 264 additions and 4 deletions
+41
View File
@@ -224,3 +224,44 @@ def test_everything_is_refused_while_mcp_is_off(
client.post(f"{PREFIX}/token", data={"grant_type": "authorization_code"}).status_code
== 403
)
def test_one_agent_can_be_revoked_without_touching_the_others(
client: TestClient,
superuser_token_headers: dict[str, str],
normal_user_token_headers: dict[str, str],
) -> None:
registered = register(client, client_name="Doomed agent")
client_id = registered["client_id"]
verifier, challenge = pkce()
code = approve(client, superuser_token_headers, client_id, challenge)
tokens = exchange(client, client_id, code, verifier).json()
def listed() -> list[dict]:
response = client.get(f"{PREFIX}/clients", headers=superuser_token_headers)
assert response.status_code == 200
return response.json()["data"]
entry = next(c for c in listed() if c["id"] == client_id)
assert entry["client_name"] == "Doomed agent"
# The column that tells an approved agent from one that only registered.
assert entry["active_tokens"] == 1
# Withdrawing access is a superuser's job.
assert (
client.get(f"{PREFIX}/clients", headers=normal_user_token_headers).status_code
== 403
)
revoked = client.delete(
f"{PREFIX}/clients/{client_id}", headers=superuser_token_headers
)
assert revoked.status_code == 200, revoked.text
assert all(c["id"] != client_id for c in listed())
# Its refresh token went with it, so it cannot mint itself a new one.
refreshed = client.post(
f"{PREFIX}/token",
data={"grant_type": "refresh_token", "refresh_token": tokens["refresh_token"]},
)
assert refreshed.status_code == 400