Forgot Password and Password Reset with Spring MVC

You’ll find a new “Forgot Password” link on the NixMash Spring Login Page, as well as the ability to reset your password on your User Profile. If you enter your account email address with “Forgot Password” and you are a valid user, a UserToken record is created and you receive an email that looks like this.

That good looking email was generated with a Velocity Template. Clicking the “Reset Your Password” link in the email takes you to a simple reset password form.

Primary Data Objects

We’re going to see two primary data objects used in the Password Reset process, UserPasswordDTO and UserToken. UserPasswordDTO is a simple container for the reset password. Because the container serves double-duty for both User Profile Password Resets and Forgot Password Password Resets, verificationToken and a userId fields are added. The verificationToken is not used with logged-in users, while the userId is a random negative number for Forgot Password users. We’ll see how that simplifies our logic in a sec.

Our UserToken Entity represents the user_tokens table, with a @OneToOne relationship to its User.

Controller Method Overview

Here are the UserPasswordController methods handling all of the Password Reset pages. We’re using a UserPasswordValidator for our userPasswordDTO object (1). Our GET and POST endpoints for the intial “Forgot Password” actions (2). At (3) Our Password Reset Form for both reset types are distinguished by the @PreAuthorize annotation for Logged-in users and the {token} @Pathvariable for users retrieving the form from email. All password updates on POST take place in changePassword().

The Endgame

We’re going to jump straight to the UserService implementation class where we’ll walk through the shared Reset Password logic. Using our trusty UserPasswordDTO container we know if the User is resetting from email or profile, where a negative userId signifies an email reset (1). If a valid userId we grab the user (2) and we’re done. Else we’ll retrieve the UserToken, validate the token by ensuring it’s not expired and the stored token’s userId in user_tokens matches the passed UserToken userId (3). Any problems along the way and our user is set to null and we return ERROR (4), otherwise we reset the password and return the appropriate response and feedback message (5).

Here’s the interplay between our Reset Password Form {POST} Controller method and the UserService actions. We’re calling the service at (1).

Logged-in users will see this feedback, while users resetting their password from an email link will be asked to log in.

Source Code Notes for this Post

All source code discussed in this post can be found in my NixMash Spring GitHub repo and viewed online here.