← back to AbramsOS

db/migrations/0001_auth.sql

52 lines

-- 0001_auth.sql — auth + 2FA tables
-- Apply: psql -d abrams_os -f db/migrations/0001_auth.sql

BEGIN;

CREATE TABLE IF NOT EXISTS auth_credential (
  id              text PRIMARY KEY,
  user_id         text NOT NULL REFERENCES user_account(id) ON DELETE CASCADE,
  password_hash   text NOT NULL,
  created_at      timestamptz NOT NULL DEFAULT now(),
  rotated_at      timestamptz,
  UNIQUE (user_id)
);

CREATE TABLE IF NOT EXISTS auth_totp (
  id              text PRIMARY KEY,
  user_id         text NOT NULL REFERENCES user_account(id) ON DELETE CASCADE,
  secret_encrypted bytea NOT NULL,
  secret_iv       bytea NOT NULL,
  secret_tag      bytea NOT NULL,
  enrolled_at     timestamptz,           -- NULL until first successful TOTP verify
  created_at      timestamptz NOT NULL DEFAULT now(),
  UNIQUE (user_id)
);

CREATE TABLE IF NOT EXISTS auth_session (
  id                  text PRIMARY KEY,        -- random, sent in cookie
  user_id             text NOT NULL REFERENCES user_account(id) ON DELETE CASCADE,
  step_up_at          timestamptz,             -- last successful TOTP step-up
  created_at          timestamptz NOT NULL DEFAULT now(),
  expires_at          timestamptz NOT NULL,
  ip                  inet,
  user_agent          text,
  revoked_at          timestamptz
);
CREATE INDEX IF NOT EXISTS auth_session_user_idx ON auth_session (user_id, expires_at DESC);

CREATE TABLE IF NOT EXISTS auth_event (
  id              bigserial PRIMARY KEY,
  occurred_at     timestamptz NOT NULL DEFAULT now(),
  user_id         text REFERENCES user_account(id) ON DELETE SET NULL,
  session_id      text REFERENCES auth_session(id) ON DELETE SET NULL,
  event_type      text NOT NULL,             -- signup, signin_pwd_ok, signin_pwd_fail, totp_enroll, totp_ok, totp_fail, step_up_ok, step_up_fail, signout, session_revoked, import_initiated
  ip              inet,
  user_agent      text,
  metadata_jsonb  jsonb NOT NULL DEFAULT '{}'::jsonb
);
CREATE INDEX IF NOT EXISTS auth_event_user_idx ON auth_event (user_id, occurred_at DESC);
CREATE INDEX IF NOT EXISTS auth_event_type_idx ON auth_event (event_type, occurred_at DESC);

COMMIT;