31 lines
1.2 KiB
MySQL
31 lines
1.2 KiB
MySQL
|
|
-- Migration 0016_jwt_revocations.up.sql
|
||
|
|
--
|
||
|
|
-- Introduces server-side JWT revocation for the SolaceScan backend.
|
||
|
|
--
|
||
|
|
-- Up to this migration, tokens issued by /api/v1/auth/wallet were simply
|
||
|
|
-- signed and returned; the backend had no way to invalidate a token before
|
||
|
|
-- its exp claim short of rotating the JWT_SECRET (which would invalidate
|
||
|
|
-- every outstanding session). PR #8 introduces per-token revocation keyed
|
||
|
|
-- on the `jti` claim.
|
||
|
|
--
|
||
|
|
-- The table is append-only: a row exists iff that jti has been revoked.
|
||
|
|
-- ValidateJWT consults the table on every request; the primary key on
|
||
|
|
-- (jti) keeps lookups O(log n) and deduplicates repeated logout calls.
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS jwt_revocations (
|
||
|
|
jti TEXT PRIMARY KEY,
|
||
|
|
address TEXT NOT NULL,
|
||
|
|
track INT NOT NULL,
|
||
|
|
-- original exp of the revoked token, so a background janitor can
|
||
|
|
-- reap rows after they can no longer matter.
|
||
|
|
token_expires_at TIMESTAMPTZ NOT NULL,
|
||
|
|
revoked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
|
|
reason TEXT NOT NULL DEFAULT 'logout'
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_jwt_revocations_address
|
||
|
|
ON jwt_revocations (address);
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_jwt_revocations_expires
|
||
|
|
ON jwt_revocations (token_expires_at);
|