-- 0019_oidc.sql -- -- OIDC bookkeeping. Three independent additions land in one -- migration to keep the related changes together: -- -- 1. users.auth_source — 'local' | 'oidc'. Local users get -- the default; first OIDC sign-in JITs -- a row with auth_source='oidc'. -- 2. users.oidc_subject — IdP's stable 'sub' claim. Indexed -- uniquely (partial; NULLs allowed). -- 3. sessions.id_token — last id_token for OIDC sessions, used -- as id_token_hint on RP-initiated -- logout. NULL for local sessions. -- 4. oidc_state — short-lived state for the OAuth round- -- trip (state + PKCE code_verifier). -- Swept on the alert engine tick. -- -- All column-level ALTERs (CLAUDE.md preference; safe under -- foreign_keys=ON). ALTER TABLE users ADD COLUMN auth_source TEXT NOT NULL DEFAULT 'local' CHECK (auth_source IN ('local', 'oidc')); ALTER TABLE users ADD COLUMN oidc_subject TEXT; CREATE UNIQUE INDEX users_oidc_subject ON users(oidc_subject) WHERE oidc_subject IS NOT NULL; ALTER TABLE sessions ADD COLUMN id_token TEXT; CREATE TABLE oidc_state ( state_hash TEXT PRIMARY KEY, -- sha256(state) hex; raw never persisted code_verifier TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE INDEX oidc_state_created ON oidc_state(created_at);