Outcome
Revoke one session belonging to the caller or a managed user.
These examples prove local handler behavior with real isolated SQL and explicitly simulated identity/permission dependencies.
Before you start
-
Verify the intended authenticated identity and the current credential-scoped action before preparing input. Self and managed-user security operations have different authority; a session id does not authorize a different user.
-
Use authorized identity and user/session discovery. Recovery security data and session/device identifiers must remain inside the caller-approved workflow.
-
Review the validated plan and intended effect before confirmation. Logout can require reauthentication; recovery verification can send an email. Fixture examples authorize no live mutation or external delivery.
Discover the target
topolo whoami --json
topolo apps --json
topolo actions get app_topolo_auth.sessions.delete --detail --json
For user/session actions use the caller subject or a user returned by authorized users discovery, then sessions.list for that exact user. For recovery read me.recovery_email.get before reviewing an approved address. Tenant identity takes no override input.
Input fields
| Field | Required | Meaning |
|---|---|---|
userId | Yes | Existing target Auth user id from authorized identity/user discovery. Self access accepts the subject or userId identity alias; managed-user access requires target-user authority. It does not authorize sessions of another user. |
sessionId | Yes | Session id copied from sessions.list for this exact user. Revocation always filters both session id and target user id, including administrator calls. Keep this sensitive security identifier inside the authorized workflow. |
Effects
-
Soft-revokes exactly the selected user/session pair, including administrator calls. An already revoked stored row can still acknowledge success.
-
Clears Auth cookies only when the self request current session cookie matches. Keeps history, other users and API-key/service-credential state.
Interpret the response
Success is HTTP 200 with raw target success/message/data/timestamp. CLI/MCP can wrap or project that response. Record timestamps are epoch seconds; the envelope timestamp is ISO text. These local fixtures simulate token identities, so no response proves live sign-in or browser OAuth recovery.
Session list uses snake_case stored columns, ordered by last_activity descending, with no limit or continuation. Default active excludes expired rows; revoked uses stored status; all includes expired records. Device JSON has variable shape and malformed/absent JSON becomes an empty object. The current store maps a SQL read error to an empty successful list, so an empty result alone cannot prove that no sessions exist.
Session delete acknowledges userId/sessionId and soft-revokes the row for the exact selected user; it does not remove history or revoke all refresh tokens/API keys. A repeated update can acknowledge an already-revoked row. currentSessionRevoked appears only for a self request whose current session cookie matches the id; that response also clears Auth cookies. The other response does not prove a different device cookie was cleared. SQL failure currently maps to NOT_FOUND.
Missing access tokens return AUTH_ERROR. A thrown invalid-token error currently becomes SERVER_ERROR in these handlers. Session/recovery/logout prefer an access cookie when present; tenant lookup prefers the Bearer header. Do not combine identities across cookie and Bearer transports or infer an OAuth expiry from every 401/500.
Worked examples
These are complete raw target-handler responses, not CLI/gateway envelopes or live authorization proof. Replace synthetic identifiers using authorized discovery. Save only the reviewed input as payload.json; inspect validation and plan before executing. --confirm assumes the intended operation is approved. Storage and response read-back require separate live token rejection, delivery and recipient verification proof where relevant. Cookies and Bearer tokens must identify the intended principal consistently.
Administrator revokes only the selected managed user session
Input · payload.json:
{
"userId": "usr_managed",
"sessionId": "session_managed"
}
CLI:
topolo actions validate app_topolo_auth.sessions.delete --data @payload.json --json
topolo actions plan app_topolo_auth.sessions.delete --data @payload.json --confirm --json
topolo actions call app_topolo_auth.sessions.delete --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.sessions.delete",
"input": {
"userId": "usr_managed",
"sessionId": "session_managed"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Session deleted",
"data": {
"deleted": true,
"userId": "usr_managed",
"sessionId": "session_managed"
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Repeated SQL revocation still acknowledges the existing revoked row
Input · payload.json:
{
"userId": "usr_managed",
"sessionId": "session_managed"
}
CLI:
topolo actions validate app_topolo_auth.sessions.delete --data @payload.json --json
topolo actions plan app_topolo_auth.sessions.delete --data @payload.json --confirm --json
topolo actions call app_topolo_auth.sessions.delete --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.sessions.delete",
"input": {
"userId": "usr_managed",
"sessionId": "session_managed"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Session deleted",
"data": {
"deleted": true,
"userId": "usr_managed",
"sessionId": "session_managed"
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Self current-cookie session revocation also clears Auth cookies
Input · payload.json:
{
"userId": "usr_self",
"sessionId": "session_current"
}
CLI:
topolo actions validate app_topolo_auth.sessions.delete --data @payload.json --json
topolo actions plan app_topolo_auth.sessions.delete --data @payload.json --confirm --json
topolo actions call app_topolo_auth.sessions.delete --data @payload.json --confirm --json
MCP call after validation and plan review:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.sessions.delete",
"input": {
"userId": "usr_self",
"sessionId": "session_current"
},
"confirm": true
}
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Session deleted",
"data": {
"deleted": true,
"userId": "usr_self",
"sessionId": "session_current",
"currentSessionRevoked": true
},
"timestamp": "2026-10-02T00:00:00.000Z"
}
Verify the result
-
List this user sessions with status all or revoked under an independently authorized current identity and require the exact id status revoked. Confirm unrelated users remain unaffected.
-
Test rejection of the old session in the actual application. deleted true alone does not prove refresh-token revocation or clearing another device cookies. Expect reauthentication if currentSessionRevoked is present.
Errors and recovery
Admin cannot revoke another user session through an authorized target URL
Captured local refusal · HTTP 404:
{
"input": {
"userId": "usr_managed",
"sessionId": "session_foreign"
},
"response": {
"success": false,
"error": {
"message": "Session not found",
"code": "NOT_FOUND",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
userId identity alias retains the exact user filter
Captured local refusal · HTTP 404:
{
"input": {
"userId": "usr_self",
"sessionId": "session_foreign"
},
"response": {
"success": false,
"error": {
"message": "Session not found",
"code": "NOT_FOUND",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Missing session cannot be revoked
Captured local refusal · HTTP 404:
{
"input": {
"userId": "usr_self",
"sessionId": "session_missing"
},
"response": {
"success": false,
"error": {
"message": "Session not found",
"code": "NOT_FOUND",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Foreign target user is refused before storage
Captured local refusal · HTTP 403:
{
"input": {
"userId": "usr_foreign",
"sessionId": "session_foreign"
},
"response": {
"success": false,
"error": {
"message": "Insufficient permissions",
"code": "FORBIDDEN",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Anonymous session write is refused
Captured local refusal · HTTP 401:
{
"input": {
"userId": "usr_self",
"sessionId": "session_current"
},
"response": {
"success": false,
"error": {
"message": "Access token required",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-02T00:00:00.000Z"
}
}
}
Published recovery guidance
-
state_conflict(HTTP 409): Read the current resource state, reconcile the intended change, and retry only if still valid. -
AUTH_ERROR(HTTP 401): Verify the intended identity and access-token transport. Refresh only an expired credential for that same approved context; do not switch organizations automatically. -
FORBIDDEN(HTTP 403): Verify target-user authority in the selected organization. Preserve the denial; session ids cannot authorize access to a different user. -
NOT_FOUND(HTTP 404): Refresh authorized user/session discovery or recovery status. Session deletion can also map a storage error to NOT_FOUND; do not claim successful revocation from this response. -
SERVER_ERROR(HTTP 500): Inspect the original error and current state. Invalid-token exceptions can return 500. A recovery write or token-version bump may already have happened; do not blindly repeat a mutation or claim a delivery/revocation outcome.
Recovery boundaries
No session un-revoke action is published. The affected user must reauthenticate normally. A repeated acknowledgment is not a new revocation proof; NOT_FOUND may reflect a missing pair or swallowed SQL failure, so preserve the original evidence and verify actual state.
Discovery and evidence
This record belongs to app_topolo_auth. Local tests prove real canonical session/recovery email SQL, target-user authorization and handler responses with simulated tokens, identity lookup and Notify results. Verification state is seeded; tokens are unusable. They do not prove live JWT rejection, browser OAuth recovery, email delivery, recipient verification, deployment or production completion.