Where should I store a username during a password reset?

This is what I usually do:

  1. The user asks for a password reset.

  2. The system asks for the registered email.

  3. The user enters email, and no matter if email exists or not, you say that you sent a reset link.

  4. The server stores email, expiration and reset token on a reset_password table

  5. When the link is accessed, expiration is checked and a form to reset the password is shown.

User only receives a link with a large random token.


You should not trust the client. So if the client is able to send their username during the stage where the new password is entered, what happens if they change the username to someone else's? They will be able to reset the account of another user and take over the account.

@ThoriumBR's answer is of course correct. Another option is to store no state on the server, and encode all information in the reset link, such as username and expiry time. This can be done securely by cryptographically signing the information, using HMAC or similar. There are likely libraries for your language that can handle this, such as itsdangerous for Python.


To add to ThoriumBR's excellent response:

  • user asks for a password reset
  • system asks for the registered email
  • user enters email, and no matter if email exists or not, you say that you sent a reset link but does not reset the password yet
  • server stores email, expiration and reset token on a reset_password table
  • when the link is accessed…
    • server checks expiration of reset token,
    • checks it has not been used before,
    • requires user to enter additional authentication tokens, could be 2FA, SMS code, answer to preset security questions, etc, and finally
    • opens a form to reset the password,
    • after which the user should be left in a "logged out" state, whereby they would need to login with the new password to access the application.
  • additionally, the server validates that the reset link was used only once within the expiration time

User only receives a link with a large random token.