Skip to content

Shared password helper

Problem

CMS centralizes bcrypt usage in apps/cms/src/lib/auth/password.ts with cost factor 12. LMS does not — bcrypt is inlined across sign-up, password-reset, and invitation-acceptance flows, and the seed script in apps/lms/scripts/db-seed.ts uses cost 10 instead of 12.

This creates two risks:

  • Drift in hashing cost between environments.
  • Inconsistent error handling (some call sites throw raw bcrypt errors).

Proposal

  1. Create apps/lms/src/lib/auth/password.ts modeled on the CMS helper:
    • hashPassword(plain: string): Promise<string> (cost 12).
    • verifyPassword(plain: string, hash: string): Promise<boolean>.
    • Throw a domain-specific error rather than the raw bcrypt error.
  2. Replace inline bcrypt calls in:
    • apps/lms/src/auth/credentials.ts (and any related auth/action modules).
    • LMS sign-up, password-reset, and invitation-acceptance server actions.
    • apps/lms/scripts/db-seed.ts — also fixes the cost-10 mismatch.
  3. Add unit tests in apps/lms/tests/unit/auth/password.test.ts.
  4. This helper will be moved into @open-learning-hub/server/password by T-006 (along with the existing CMS one); landing app-locally first keeps T-006 a pure extraction.

Acceptance criteria

  • All LMS bcrypt call sites import from @/lib/auth/password.
  • No raw bcrypt.hash / bcrypt.compare calls remain in apps/lms/src/** or apps/lms/scripts/**.
  • Seed script uses cost 12.
  • New tests pass; npm run check passes.

Out of scope

  • Migrating existing low-cost hashes in user data (kept as-is; users will be re-hashed on next password change).
  • Sharing the helper with CMS (handled by T-006).
  • Password policy / strength rules.

Notes / decisions log

  • 2026-05-24: Ticket created from monorepo audit.
  • 2026-05-25: Implemented apps/lms/src/lib/auth/password.ts mirroring CMS (cost 12, no error wrapping). Replaced inline bcrypt in credentials, sign-up, reset-password, accept-invitation, account actions, and scripts/db-seed.ts (10→12). Added tests/unit/auth/password.test.ts. npm run check green.