Skip to content

sessions

Tracks signed-in clients in the read_user_sessions table (one row per JWT, keyed by the sid/jti claim) and exposes handlers for mine (list your sessions), revoke, and revokeAllOthers. Session creation and revocation on the hot auth path are handled by createSessionCallbacks(), wired into buildServer({ auth: { ... } }) outside the dispatcher; the feature also ships a manual-trigger cleanup job for pruning expired rows and an optional autoRevokeOnPasswordChange hook that mass-revokes all sessions for a user whenever their passwordHash changes.

From recipes-session-revocation — the smallest working mount:

// Session Revocation Sample
//
// Shows the production-wiring shape: an app builds `createSessionCallbacks()`
// against a live DB handle, then hands the creator/revoker/checker to
// `buildServer({ auth: ... })`. From there the framework handles the rest —
// login persists a sid, the middleware checks it on every request, logout
// flips the DB row, a forged JWT without a matching session is rejected.
//
// What to copy into your own app:
//
// const db = createDbConnection(config.databaseUrl);
// const callbacks = createSessionCallbacks({ db });
// const server = buildServer({
// registry: buildRegistry([
// // Pass the mass-revoker into the sessions feature to wire
// // "password-change signs you out everywhere" — the feature registers
// // a cross-feature entity-hook on the user entity that runs it.
// createSessionsFeature({
// autoRevokeOnPasswordChange: callbacks.sessionMassRevoker,
// }),
// // ... other features
// ]),
// context: { db, ... },
// jwtSecret: config.jwtSecret,
// auth: {
// membershipQuery: "tenant:query:memberships",
// loginHandler: "auth-email-password:write:login",
// sessionCreator: callbacks.sessionCreator,
// sessionRevoker: callbacks.sessionRevoker,
// sessionChecker: callbacks.sessionChecker,
// },
// });
//
// Design rules the sample demonstrates:
//
// 1. Sessions are a feature, not built-in. An app that doesn't register
// `createSessionsFeature()` (or doesn't wire callbacks) issues plain
// stateless JWTs — valid until expiry, no revocation path.
// 2. Session storage is abstracted behind the three callback signatures.
// This sample uses the default DB-backed impl; you could swap in a
// Redis- or Memcached-backed version by wiring your own callbacks that
// match `SessionCreator`/`SessionRevoker`/`SessionChecker`.
// 3. The `jti` claim on the JWT is the link between stateless token and
// stateful server. The middleware never trusts the JWT alone when a
// checker is wired — it confirms the sid is still live.
export {
createSessionCallbacks,
createSessionsFeature,
} from "@cosmicdrift/kumiko-bundled-features/sessions";

📄 On GitHub: samples/recipes/session-revocation/src/feature.ts

What this feature needs to run (Requires, top) and the write commands it provides (Provides, bottom).

flowchart TB
  n_sessions["sessions"]
  subgraph how_reqs["Requires"]
    n_user["user"]
  end
  subgraph how_provides["Provides"]
    n_cmd_sessions_write_user_session_revoke(["revoke"])
    n_cmd_sessions_write_user_session_revoke_all_for_user(["revoke-all-for-user"])
    n_cmd_sessions_write_user_session_revoke_all_others(["revoke-all-others"])
  end
  n_user --> n_sessions
  n_sessions --> n_cmd_sessions_write_user_session_revoke
  n_sessions --> n_cmd_sessions_write_user_session_revoke_all_for_user
  n_sessions --> n_cmd_sessions_write_user_session_revoke_all_others

Provides — write commands this feature registers (dispatch them through the command bus):

Start with recipes-session-revocation for a step-by-step walkthrough with runnable code and integration tests.

  • Requires: user
  • Activation: always on (not toggleable)
  • Exposes API: sessions.revokeAllForUser