feat(auth): add per-instructor accounts and local password login
Replaces the single shared ADMIN_PASSWORD (Phase 2B) with real accounts: instructors table (email/display_name/role/status), scrypt password hashing with a fresh random salt PER INSTRUCTOR (Phase 2B used one fixed salt because there was exactly one shared password — that assumption is gone), auth_identities table so a future OIDC login can map to the same instructor_id without a schema change. New POST /api/auth/instructor/login, POST /api/auth/logout, GET /api/auth/session, POST /api/auth/change-password (old password required, revokes other sessions). No account enumeration: identical response whether the email doesn't exist or the password is wrong. bootstrap-owner.js is the only supported way to create the first account — no manual database editing to stand up a fresh deployment. Refuses to run if an active owner already exists unless the target email is an existing instructor (zero-owners recovery path).
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
-- auth_identities — lets a local-password identity and a future OIDC identity map to the same
|
||||
-- instructor record without a schema change when OIDC lands. Every instructor gets a 'local'
|
||||
-- row today (provider_subject = their own instructor_id as text); a Google/OIDC login later
|
||||
-- just adds a second row for the same instructor_id. See
|
||||
-- docs/PHASE3A_IDENTITY_AND_INSTRUCTOR_ACCESS.md for the adapter interface this backs.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS auth_identities (
|
||||
auth_identity_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
instructor_id UUID NOT NULL REFERENCES instructors(instructor_id) ON DELETE CASCADE,
|
||||
provider TEXT NOT NULL, -- 'local' | 'google' | 'oidc:<name>'
|
||||
provider_subject TEXT NOT NULL,
|
||||
provider_email TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
last_login_at TIMESTAMPTZ,
|
||||
UNIQUE (provider, provider_subject)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_auth_identities_instructor ON auth_identities(instructor_id);
|
||||
Reference in New Issue
Block a user