Skip to content

Latest commit

 

History

History
48 lines (36 loc) · 1.99 KB

File metadata and controls

48 lines (36 loc) · 1.99 KB

RequestPasswordResetUsecase

Objective

Accept a public forgot-password request and always return a non-disclosing success response while conditionally issuing a one-time reset token and sending the transactional email when the account exists.

Execution Context

  • Public GraphQL mutation (password_reset_request) exposed through UserResolver.
  • No authenticated session required.
  • Abuse protections required: honeypot, CAPTCHA verification, anti-abuse rate limiting.

Business Access Rules

  • Input honeypot must remain empty.
  • CAPTCHA token must be valid and non-replayed.
  • Public source key must pass anti-abuse rate limit.
  • Response contract must be identical whether the email exists or not.

Algorithm Steps

  1. Reject request when honeypot is filled.
  2. Verify CAPTCHA token via VerifyCaptchaTokenUsecase.
  3. Check anti-abuse limiter using the source key (IP-based).
  4. Resolve user by submitted email.
  5. If user exists:
    • generate unique jti,
    • sign reset JWT (60 minutes) with minimal claims + UX fields,
    • store jti in local reset-token cache with aligned TTL,
    • build URL ${fo_url}/reset?jwt=<token>,
    • resolve email template language from user country (fr for FR-like locales, otherwise default en),
    • send FitdeskForgotPassword email through Morgans service.
  6. Return { ok: true, messageKey: 'password_reset.request.sent_if_exists' }.

Handled Errors

Error Cause
PASSWORD_RESET_REQUEST_HONEYPOT_TRIGGERED Honeypot field is not empty
INVALID_CAPTCHA_TOKEN CAPTCHA verification failed
PASSWORD_RESET_REQUEST_RATE_LIMITED Source exceeded anti-abuse limit
REQUEST_PASSWORD_RESET_USECASE Unexpected failure (fallback)

Business Guarantees

  • Non-disclosing behavior: clients cannot infer account existence from the success payload.
  • Replay mitigation starts at issuance time by storing jti in process-local cache.
  • Reset tokens are intentionally volatile across API restarts (accepted single-instance tradeoff).