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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user