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:
2026-08-18 13:35:54 -05:00
parent 52c17c1907
commit 85fa920f96
8 changed files with 323 additions and 30 deletions
+2 -1
View File
@@ -6,7 +6,8 @@
"main": "src/server.js",
"scripts": {
"start": "node src/server.js",
"migrate-sqlite": "node migrate-sqlite.js"
"migrate-sqlite": "node migrate-sqlite.js",
"bootstrap-owner": "node bootstrap-owner.js"
},
"dependencies": {
"express": "^4.19.2",