Files
support_backend/src/modules/identity/auth/mapper/reset-token.ts
T
saqib mirandClaude Sonnet 5 79bc2ef25b feat(013-auth-hardening): password reset, password strength policy, login rate-limiting
Closes the two gaps 010-identity-auth explicitly deferred (password reset,
login rate-limiting), plus a shared password-strength validator both the
reset-consume endpoint and admin account creation now depend on.

- Password reset: single-use, paired-Redis-key tokens (never in Postgres),
  identical response regardless of account existence, stubbed delivery via
  a structured log line (no email infrastructure exists yet).
- Password strength: one validatePasswordStrength() call site, wired into
  both POST /admin/users and the reset-consume flow.
- Login rate-limiting: checkRateLimit keyed by submitted email, checked
  before any credential verification.

Also fixes tests/helpers/auth.ts's shared loginAs() helper, which reused
two fixed accounts across the whole integration suite via upsert — now
rate-limited per email, that collided across ~30 files sharing one budget.
Each call now gets a unique email; no call sites needed to change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 21:22:49 +05:30

19 lines
688 B
TypeScript

import { randomBytes, createHash } from 'crypto';
export interface GeneratedResetToken {
token: string;
tokenHash: string;
}
/** 013-auth-hardening: the raw token is what gets "delivered" (logged, per the stub decision,
* research.md); only its SHA-256 hash is ever persisted (data-model.md) — mirrors this
* codebase's own password-hashing discipline, never storing a usable secret at rest. */
export function generateResetToken(): GeneratedResetToken {
const token = randomBytes(32).toString('hex');
return { token, tokenHash: hashResetToken(token) };
}
export function hashResetToken(token: string): string {
return createHash('sha256').update(token).digest('hex');
}