Closing live connections — WebSocket and SSE — when the credential behind
them is revoked.
Why this exists. A WebSocket and an SSE stream are authorized once, at
open. Per-message WebSocket dispatch (actions/perform_action.ts) reloads
role grants, never the session or token, and a one-way stream re-reads
nothing. So a revocation takes effect on an open connection only when
something closes it. ConnectionCloser is that capability, and every
revocation handler holds one: the session and token revokes, the revoke-alls,
account delete and purge, /logout, /password, and the session and token
caps for what they evict. The auth cleanup holds one too
(AuthCleanupDeps.connection_closer): its session sweep closes the
connections of each expired session it deletes, after that delete commits.
Closing after commit
A revocation runs inside a request transaction, and it must not close a
connection until that transaction commits. queue_connection_close defers
the close onto the request's post-commit queue (emit_after_commit): it
runs after the commit and is dropped on rollback, so a revocation that never
happened closes nothing.
Two things rest on that order. A client told "revoked" rechecks its session
straight away, and before the commit the row it probes is still there. And
connection admission registers a connection and then re-reads its
credential (revalidate_resolved_auth): a close that missed the
registration must belong to a revocation the re-read can see, which holds
only if the close came after the commit.
Why the handlers close directly
The audit listeners (create_ws_auth_guard, create_sse_auth_guard) close
connections too, but only once the audit row is written, and that write is
pool-routed and fail-open. The handler's own close is the one that runs
whatever happens to the audit write, so the closer it holds must reach every
transport whose connections outlive their credential. RealtimeCloser is
that fan-out, and create_app_backend puts one on AppDeps.
Twin of the Rust spine's SocketRevoker, SocketCloseTarget,
queue_socket_close, and RealtimeRevoker.