2.0 KiB
2.0 KiB
Security Forgot Password Controls
Implemented Controls
- Public entry points:
POST /auth/forgot-password/requestPOST /auth/forgot-password/confirm
- Enumeration resistance:
- Request endpoint always returns
200with a generic success message. - No account existence signal for unknown/unverified emails.
- Request endpoint always returns
- Verified-account gate:
- Reset tokens are issued only when
emailVerified=true.
- Reset tokens are issued only when
- Token security:
- Reset links contain
uidand rawtokenin query params. - Server stores only
SHA-256(token). - Token type is
password_reset. - Token must match
uid, be unused, and be unexpired. - Token is consumed once (
usedAt) and cannot be reused.
- Reset links contain
- Session invalidation:
- Added
User.passwordChangedAt. - JWT auth middleware rejects tokens with
iat <= passwordChangedAt. - Reset and authenticated password-change both set
passwordChangedAt.
- Added
- Abuse controls:
- Request endpoint: per-IP + email-fingerprint route keying.
- Confirm endpoint: per-IP + uid-fingerprint route keying.
- Endpoint-specific rate limits via env config.
- Logging hygiene:
- Structured security events for request/email/confirm outcomes.
- No plaintext password or raw token in logs.
- Misconfiguration resilience:
- Email send failures do not leak through API response shape.
- Generic response is preserved if SMTP is unavailable.
Environment Settings
PASSWORD_RESET_TTL_MINUTES(default30)PASSWORD_RESET_RATE_LIMIT_PER_MINUTE(default5)PASSWORD_RESET_CONFIRM_RATE_LIMIT_PER_MINUTE(default10)
Operational Verification
- Verify
/auth/forgot-password/requestalways returns the same JSON for unknown, unverified, and verified addresses. - Verify only verified users get
EmailToken(type=password_reset)rows. - Verify
confirmsucceeds once and fails on replay. - Verify pre-reset session cookies fail on protected routes after successful reset.
- Verify security logs contain
auth.password_reset.*events and no raw token values.