Session management
List active sessions and revoke single, per-user, or tenant-wide refresh tokens.
Five endpoints under /api/v1/tokens let an admin inspect and end
sessions inside a tenant. All accept dual authentication (JWT or Client
Key with X-Tenant-Code) and require the tokens:read or
tokens:revoke permission.
| Operation | Method | Path | Permission |
|---|---|---|---|
| List sessions | GET | /tokens | tokens:read |
| Revoke a single session | POST | /tokens/:tokenId/revoke | tokens:revoke |
| Revoke all sessions for a user | POST | /tokens/revoke-user/:userId | tokens:revoke |
| Revoke every session in the tenant | POST | /tokens/revoke-all | tokens:revoke |
Revocation is recorded with revoke_reason = MANUAL_REVOKE and emitted
to the audit log alongside the actor.
Listing sessions
GET /api/v1/tokens?active=true&limit=50&offset=0
Authorization: Bearer <jwt-with-tokens:read>Filters: userId (UUID), active (true = non-revoked and
non-expired only; omit for all), limit (1–100, default 50), offset
(default 0).
{
"success": true,
"data": {
"tokens": [
{
"id": "01HXT...",
"userId": "01HXY...",
"userEmail": "alice@acme.com",
"expiresAt": "2026-05-29T18:14:02.103Z",
"revoked": false,
"createdAt": "2026-05-22T18:14:02.103Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}
}The row id is the refresh-token UUID — pass it to the revoke endpoint
to end that specific session.
Revoking a single session
POST /api/v1/tokens/01HXT.../revoke
Authorization: Bearer <jwt-with-tokens:revoke>{ "success": true, "message": "Token revoked" }404 with NOT_FOUND if the tokenId doesn't exist in the caller's
tenant. The client whose token was revoked sees INVALID_TOKEN (401) on
the next /refresh. Any access token already in the client's hand keeps
working until its exp — at most 15 minutes by default.
Revoking all sessions for a user
POST /api/v1/tokens/revoke-user/01HXY.../revoke
Authorization: Bearer <jwt-with-tokens:revoke>Wait — the path is:
POST /api/v1/tokens/revoke-user/01HXY...The response includes the count:
{ "success": true, "message": "3 tokens revoked" }Use this when a user account is compromised, a person leaves the organization, or a credential change should not require waiting for each device's refresh cycle.
Revoking every session in the tenant
POST /api/v1/tokens/revoke-all
Authorization: Bearer <jwt-with-tokens:revoke>{ "success": true, "message": "247 tokens revoked" }Tenant-wide impact
Every user in the tenant must re-authenticate. Use only on security incidents (suspected breach, JWT secret compromise) or as the last step of a planned cutover.
Permissions
tokens:read and tokens:revoke are not granted by default to standard
roles. Add them to an admin role explicitly:
POST /api/v1/roles/:id/permissions
Authorization: Bearer <jwt-with-roles:update>{ "permissionNames": ["tokens:read", "tokens:revoke"] }Or grant them to an individual user via POST /permissions/grant.
Pairing with the audit log
Every revocation appends a row to auth_logs. Query it to see who
revoked what:
GET /api/v1/auth/logs?action=LOGOUT&userId=01HXY...&startDate=2026-05-15T00:00:00Z&endDate=2026-05-23T00:00:00ZThe userAgent and ipAddress columns on the revoked token row also
remain visible via GET /tokens?userId=...&active=false — useful when
investigating which device was forced off.