Make revoking an agent and locking a dashboard actually revoke and lock
An MCP access token is a stateless JWT good until it expires, so deleting the client row revoked nothing already handed out — on the MCP endpoint or on the REST API, which takes the same token directly. Both doors now look the client up by the `client_id` the token has always carried, so tokens already in circulation are held to it too. A dashboard's `locked` setting stopped the client drawing a control and nothing else; the server took a publish from a panel showing it anyway. It now bounds the panel's write scope, resolved live where a flow drives the flag, exactly as the client resolves it. Reads are untouched — read-only is not blind — and so is a querying chart's request, which is how that tile reads rather than something anyone touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CL9zvnnvcp1mvA8o7impxk
This commit is contained in:
@@ -270,6 +270,17 @@ def test_one_agent_can_be_revoked_without_touching_the_others(
|
||||
assert revoked.status_code == 200, revoked.text
|
||||
assert all(c["id"] != client_id for c in listed())
|
||||
|
||||
# And the access token already in its hands stops working, rather than
|
||||
# outliving the revocation by up to MCP_TOKEN_EXPIRE_MINUTES: the token is
|
||||
# stateless, so the client row it names is what withdrawing it removes.
|
||||
assert (
|
||||
client.post(
|
||||
f"{settings.API_V1_STR}/login/test-token",
|
||||
headers={"Authorization": f"Bearer {tokens['access_token']}"},
|
||||
).status_code
|
||||
== 401
|
||||
)
|
||||
|
||||
# Its refresh token went with it, so it cannot mint itself a new one.
|
||||
refreshed = client.post(
|
||||
f"{PREFIX}/token",
|
||||
|
||||
Reference in New Issue
Block a user