Update 2/29/16: These code examples have been updated to reflect the 3.0 release of the express-stormpath integration.
I’ve built many Express applications recently, and it’s reminded me of the pains of building password reset functionality since there are many Express tools for handling it. Building password reset is a drag for most developers, every application needs it, and getting it wrong can have a major impact on your application. This post is an effort to reduce the pain of building password reset for other node developers by first describing the systems you’re going to need and then offering a recommended workflow for password reset.
Systems Needed for Password Reset
For starters, Express requires you to build out a proper user system. Your first reaction would be to use Passport, but you’ll quickly find that Passport does not store accounts — you still have to do that yourself. Passport is good for adding authentication strategies (like Facebook vs username/password) if you already have a user management system in place. So, get coding.
With a user system in place, you start to build password reset. First, you need several additional routes for the pages in the password reset flow, and to include input validation and CSRF protection for your forms.
Then you’re going to need an email component to send the user their secure URLs and tokens. If you don’t already have email built into your application, you might want to use an email service like Sendgrid or Mailgun. Next, email templates for each part of the reset process.
Almost there. You now need to get those reset tokens working. First, you need the logic to create unique tokens for each reset attempt and expire them within a certain time frame and on first use. That will include an additional table to store the tokens and their expiration metadata. Then build the logic in your code to authenticate and verify those tokens before a reset can be completed.
All in all, it’s dozens of hours of work (possibly more) you would probably rather spend on core application business logic.
And while it’s not rocket science, hand-rolled password reset workflows can be error prone and those errors directly translate to vulnerabilities in your application — user accounts can be hijacked. Since password reset is not core to most applications, these types of vulnerabilities are often not discovered until they actually get exploited.
So, let’s talk about how to build it the right way.
Password Reset Workflows – The Right Way
Over the years I’ve used numerous password reset systems, and there is really only one good way to handle password reset functionality in your web applications.
Here’s how we recommend you do it:
- On your login page, there should be an obvious “Forgot your password?” link. Otherwise you’ll confuse users and increase either support tickets or abandonment.
When a user gets to your password reset page, and enter their email address. You may want to ask for a second factor to identify the user at this stage or a later stage.
After the user has entered their email address, send them an email with a link to the password reset page on your site. This link should contain a unique password reset token that expires after a certain amount of time and one first use. If your token isn’t unique, doesn’t expire — you’ve got a very real vulnerability on your hands.
After you’ve sent the user an email, give them a message telling them what to do! Tell the user you sent them an email, and tell them to check their inbox. If you immediately redirect them somewhere else, they’ll be confused!
After the user clicks the link in their email, they should be brought to a page on your site that prompts them to enter a new password. Ensure you make the user enter their new password twice so they don’t forget what they just typed. Make sure you validate their token before proceeding! If the token isn’t valid, you should display an error message and instructions on how to proceed.
Once the user has reset their password, give them a confirmation message to eliminate confusion. “Your password has been reset” is typically good enough.
Lastly, ensure you send the user an email once their password has been changed letting them know what happened. This will ensure the user knows what they did, and is a great auditing tool in the future. It’s also an easy alert in the event the user didn’t initiate the reset themselves.
If any of these steps is missing, you may confuse your users and open yourself up to security vulnerabilities.
Take the token, for instance. If this token isn’t validated — that means anyone can reset one of your user’s passwords — and that’ isn’t a good thing.
If your tokens don’t expire after a short period of time (usually 24 hours), then you’ve got an issue. What if this user’s email gets compromised in the near future? What if the token can be easily guessed?
And lastly, if your token isn’t actually unique — you’ll be in for some embarrassing work meetings. For instance, I’ve noticed that many sites set the password reset token to a guessable number! For instance, if you use an incrementing integer value (1, 2, 3, …), it’s quite easy for attackers to guess at these numbers until they find a valid one.
NOTE: It’s also worth mentioning explicitly that you should NEVER send your users an email containing their password. This means that you’re more than likely storing your passwords in plain text (an awful idea), and exposes users to additional risk: what happens if someone looks over their shoulder as they read their email and sees their password? That doesn’t just happen in movies.
Stormpath’s Password Reset Workflow
The Stormpath API has always handled password reset for developers so you don’t have to go through this pain. And we have a great ExpressJS integration. And… I just added password reset to it, so you don’t have to!
If you aren’t familiar with Stormpath, we’re API service you can use to deploy complete user management in your application — login, user profiles, password reset, Facebook integration, etc. And it’s all under the hood, your end-users never know we exist.
Our popular express-stormpath library fully supports password reset. You can instantly add password reset into your ExpressJS web applications with a single line of configuration information:
// Optional configuration, see documentation
After enabling the password reset functionality with the Stormpath middleware, a magical link will appear on your login page that allows users to start the password reset process.
Below are some screenshots that demonstrate what users will see with the baked-in views (100% customizable, of course):
If you’d like to check it out, give some feedback, or point out ways to improve the new Express integration, please take a look at the new password reset documentation and let me know what you think.