KemalIdentity::Postgres::SessionRepository
Inherits KemalIdentity::Sessions::Repository < Reference < Object
Sessions::Repository over auth_sessions.
The hot path is #find_by_digest, and it is the one query whose cost lands on every
authenticated request. Everything else runs at login, at logout, or in a background sweep.
Constants
PostgreSQL's SQLSTATE for a unique violation.
Constructors
accounts_table exists because auth_accounts is a reference implementation. An
application authenticating against its own users table joins against that instead, and
still satisfies the same contract — the contract spec asserts the result shape, never the
SQL.
Instance methods
Stores a new session.
Raises KemalIdentity::InfrastructureError if record.token_digest is already present.
This is not defensive noise: auth_sessions.token_digest carries a unique index
precisely so that a digest collision is a loud database error rather than a silent
security failure in which two accounts share a session
(docs/03-data-model.md). An implementation that upserted here would convert that
error into exactly the failure the index exists to prevent.
Deletes rows whose absolute_expires_at is at or before before, returning the count.
Disk reclamation only. Correctness never depends on this having run: expiry is
evaluated on every read, which is the direct lesson of kemal-session issue #116, where
a timeout only marked a session for deletion at the next GC pass and a read could
refresh its access time before any expiry check, reviving it
(docs/02-security-model.md).
Deletes revoked rows whose revoked_at is at or before before, returning the count.
Separate from #delete_expired because a revoked session is not necessarily an expired
one: logging out at nine in the morning revokes a row whose absolute deadline is still
hours away, and that row is worth keeping for a while. It is the evidence behind "you
were signed out of this device", and deleting it the instant it is revoked throws away
the only record that the logout happened.
The retention window is the application's to choose. Disk reclamation either way — correctness never depends on this having run, because revocation is evaluated on read.
One indexed lookup with a join, returning session state and account status together.
Decision D7. Fetching the session and then fetching the account is two round trips on
every authenticated request, which roughly doubles the fixed cost of every page view for
no benefit (docs/03-data-model.md).
An inner join, so a session pointing at an account that no longer exists resolves to nothing: the failure mode is closed rather than open.
Marks one session revoked, returning false if it does not exist or was already revoked.
Already-revoked returns false rather than raising: logging out twice is not an error, and the caller learns whether it changed anything.
Revokes every live session for an account, optionally sparing one, and returns how many it revoked.
except_id is what makes "log out everywhere else" and "change password without
logging myself out" possible. Already-revoked sessions are not counted and not
re-stamped, so the count is the number of sessions actually ended.