Web applications commonly require that users register using a valid email address. A working email address is crucial for common tasks, such as resetting passwords and account management. Email verification is also essential for ensuring signups are from real users.
The purpose of this article is to provide a high-level overview on implementing email verification using Node, Express, and MongoDB. This tutorial will be using Mongoose as a ORM for MongoDB and NodeMailer for sending out emails.
Node Express MongoDB
This tutorial is meant to act as a general guide. Most likely, implementation details will vary based on your Node application.
It’s not rocket science, but here’s the verification workflow we’ll be using.
  1. A user registers for an account. The user is created, but the user still needs to be verified via an email confirmation. The user cannot login until their account is verified.
  2. A verification token is emailed to the user.
  3. The user receives the verification email in their inbox. A link is provided in the email that passes the verification token back into your application.

Creating Your Models

We’re going to need to make a couple of modifications to your database to support email verification.

Tracking Verification In Your User Model

To get rolling, we’re going to need a way to distinguish which users have been verified. To track verification, we’re going to add a new isVerified flag to the User model. Notice that the default value for isVerified is false.

Create Token Verification Model

When a user signs up, we’re going to create a verification token within Mongo. We need a new model to handle our verification tokens.

There are a couple of interesting points regarding our verification tokens:
  • Not surprisingly, you will need to provide the userId of the user the token is issued.
  • More interesting, there is a powerful feature in Mongo called “expires” that sets a documents time to live, known as TTL. In the model above, the TTL expires attribute is set to 43200 seconds, meaning the verification token document will automatically delete itself after 12 hours. This means users will have 12 hours to activate their accounts before their verification tokens expire. If a user doesn’t confirm their account in time, they can request a new verification token.

Registering Additional Routes in Express

In addition to your normal Sign Up and Login functions, we’re going to need two new routes in Express.

The first route will be used for token confirmation. The second route will be used in case a user needs to resend a new confirmation token.

Tying Everything Together In Node

The majority of work to implement email verification is done in Node.

Log In

First, we need to add a small bit of logic to our login function to ensure all users have been verified. If a user has not been verified, return a status code of (401) Unauthorized with the appropriate message.

In the example code below, we’re using token based authentication. It would be easy to change the code to use Passport instead. Really, all you need to do is modify your login code to check for isVerified.

Sign Up

When a user signs up, instead of logging them in immediately we are going to email them a confirmation token to ensure they provided a real email.

We’re using a couple of packages, crypto and nodemailer, to assist in token creation and emailing.

Token Confirmation

You are also going to need a Node function for confirming verification tokens. It’s important to remember that based on the TTL in our model that verification token will automatically delete themselves after a set period of time.

For an extra layer of security, I prefer to have the confirmation link take the user to a token confirmation form. The user would be asked to provide their email. The confirmation token would be embedded in this form as a hidden input. The submission of this form would post to confirmationPost below. For brevity’s sake, this confirmation form is not included in this tutorial.

If you prefer, you can have the user automatically confirm the token by clicking the link, but the action below would need to become a Get, instead of a Post.

Resending Tokens

It’s inevitable that some users will not be able to verify their account before their token expires. We’re going to need a mechanism for reissuing confirmation tokens.

Voila! Your Node App Now Has Email Verification

Your web application is now ensuring users register with real, operational email addresses. This should help in keeping out some of the riff-raff and make sure users can regain account access when needed.

Again, this tutorial was meant to provide a high-level guide and the implementation details will most likely vary based on the specifics of your Node application.

Notify of
Newest Most Voted
Inline Feedbacks
View all comments
Mark Niles
4 years ago

This concise article was perfect for me getting email verification stitched into my MEAN app. Thanks for taking the time to put this together.

Jim Marstick
Jim Marstick
3 years ago

Just what I needed. Clearly written and it works! Helped me out big time.

Lou Godard
Lou Godard
3 years ago

Nice job. You just saved me a bunch of time. Much appreciated. Cheers!

Mike Tase
Mike Tase
3 years ago

Thanks much man. This saved me alot of time and effort. Good job.

Pitch A.
Pitch A.
3 years ago

Thank you Josh! This is exaclty what I was looking for.

Kingdom Orjiewuru
Kingdom Orjiewuru
3 years ago

Thanks for sharing this Josh. It really helped me get my email verification done.

3 years ago

This is the best tutorial I’ve found covering email verification. Love it.

Peter Tichelaar
Peter Tichelaar
2 years ago

cheers Josh, your instruction helped me a lot! Peter

2 years ago

Thank you very much Josh! This is what I am looking for!

Obie Bryant
Obie Bryant
2 years ago

Hello, this little tutorial has been most helpful. So concise and right on point. Little question however, do i need to install express-validator to ensure methods like
req.assert(’email’, ‘Email is not valid’).isEmail() will work?
if I make the required in the model, is it even necessary?

Dong Mai
2 years ago

thanks for the article, it’s really useful for me.

1 year ago

perfect article !! thanks a lot

1 year ago

Crystal clear post. You are a real teaching genius man. Thank’s…

Saad Abbasi
8 months ago

Thank you for your precise and and well explained tutorial 👍.

Mohammed Osman
Mohammed Osman
6 months ago

Thank you so much for this article

3 months ago

Hi Josh Greenberg,
Thank you so much for this guide, I’ve tried to implement this on my project, it kept throwing ‘ReferenceError: Token is not defined’.
Is there something I’m doing wrong?

I also tried to import Token by doing this ‘const Token = require(‘./model/userToken’); but it threw OverwriteModelError: Cannot overwrite Users model once compiled.

Please I need your help, I guess I’m doing somethings the wrong way, but I can’t seem to figure it out.

I just want to create a token after a user is registered successfully and use this token in the future

Get in touch! We would love to discuss your next software project.
Would love your thoughts, please comment.x