-- Server-side session revocation for a stateless JWT.
--
-- Until now a token was valid until it expired, full stop. Changing a password
-- did not end existing sessions, resetting a forgotten password did not end
-- them either, disabling an account did not end them, and /auth/logout returned
-- 200 while doing nothing at all — the client simply dropped its own copy. A
-- token copied off a shared machine stayed usable for the rest of its 24 hours
-- no matter what the owner did about it.
--
-- The fix is one timestamp per user rather than a table of revoked tokens.
-- Every token carries an "iat" (issued-at) claim; any token issued before this
-- moment is refused. That means:
--
--   * one row per user instead of one row per revoked token, so nothing grows
--     without bound and no cleanup job is needed;
--   * revoking is a single UPDATE, which makes it cheap enough to do on every
--     password change, reset, deactivation and logout;
--   * a blocklist's usual failure — forgetting to add a token to it — cannot
--     happen, because the default is that everything older is dead.
--
-- The trade-off is deliberate: this cannot revoke one device while leaving
-- another signed in. Logging out ends every session for that account. On a
-- journal with a handful of editors that is the safer default anyway, and it is
-- the behaviour someone actually wants when they log out of a shared computer.
ALTER TABLE users ADD COLUMN tokens_valid_from TIMESTAMPTZ;

COMMENT ON COLUMN users.tokens_valid_from IS
  'Tokens issued before this instant are rejected. NULL means nothing has been revoked yet.';
