KemalIdentity::Postgres::RememberRepository
Inherits KemalIdentity::Sessions::RememberRepository < Reference < Object
Sessions::RememberRepository over auth_remember_tokens.
#consume is two statements, and their order is the whole correctness argument.
The conditional UPDATE goes first. It is what makes spending atomic: any number of
concurrent callers reach it, PostgreSQL serialises them on the row, and exactly one finds
used_at IS NULL still true. Only when it changes nothing does the second statement look
up why — and by then the answer is stable, because a token that has been spent stays spent.
Doing the lookup first would be the read-then-write race that lets two callers both spend one token, which here would mean a stolen cookie working silently instead of being detected.
Constants
Constructors
Instance methods
Spends the token with this digest, or reports why it could not.
Returns RememberAccepted exactly once per token. Every later presentation of the same
digest returns RememberReplayed, until the row is swept.
An expired or revoked token returns RememberUnknown rather than a replay: neither is
evidence of theft. An expired token is somebody returning after a month, and a revoked
one is a family already killed — reporting that as a fresh detection would send a second
alarm for the same incident.
Stores a newly minted token.
Raises KemalIdentity::InfrastructureError on a duplicate digest.
Deletes rows past their expiry, returning the count.
Disk reclamation, with one caveat that matters: a spent token must survive at least as long as its expiry, or replay detection stops working. Delete it early and a stolen token that comes back looks unknown rather than replayed, and nobody is told.
Kills every token for an account, across all families. "Forget me everywhere", and the right response to a password change.
Kills every token in a family, returning how many it killed.
The response to a replay. It ends that browser's remembered state — including the thief's — and leaves the account's other devices signed in, because a stolen cookie on one machine says nothing about the others.
Kills the family that this token belongs to, without spending the token, and returns how many it killed.
This is what logging out calls. Consuming the token instead would mark it used, and the browser's next visit with the same cookie would then look like a replay — the user would be told their cookie may have been stolen because they pressed "log out".
Returns zero when the digest is unknown.