Password reset flow
The forgot-password path: an emailed one-time link that expires, lets you set a new password, then stops working.
See it
What it is
The forgot-password path, done properly. Someone types their email, you mail a one-time token that expires fast (15 to 60 minutes is typical), they open it, set a new password, and the token dies on use. Store only a hash of the token, never the token itself, and store the new password only under a real password-hashing function: Argon2id first, with bcrypt, scrypt, or a PBKDF2 configuration that meets your policy as perfectly respectable alternatives.
The security work is mostly in what you do not say. The 'did you forget your password' form must return the same message whether the address exists or not, otherwise it becomes a free account-enumeration API. Rate limit by address and by IP, since the endpoint sends real email on demand and makes a lovely mail bomb.
Gotcha most people miss: a successful reset should invalidate every existing session and refresh token, and any pending reset tokens. The whole point is that an attacker may already be logged in. Also decide up front what a reset does to MFA, because letting an emailed link bypass the second factor quietly downgrades your entire login to 'whoever controls the inbox'.
Ask AI for it
Build a password reset flow. Request step: a form that takes an email and always responds 'if that account exists we sent a link', with rate limiting per email and per IP. Generate a random token, store only its SHA-256 hash plus a 30 minute expiry and a used_at column, and email /reset?token=... Reset step: validate the token, enforce a minimum password length, hash the new password with Argon2id (or bcrypt, scrypt, or a policy-compliant PBKDF2 configuration if Argon2id is not available in this stack), mark the token used, revoke all existing sessions and refresh tokens for that user, and send a 'your password was changed' notification email. Keep MFA required after reset.