loading...

How to verify your users' email addresses | Node.js/Express

christopherliedtke profile image Chris ・4 min read

When you build an application there is a good chance that you'll want to restrict access to certain parts of it. You'll need to set up a user authentication system and protect certain routes in your app.

It is quite common to use the user's email address as a unique identifier during your registration process. As no two people can have the same email address that is a very valid approach. However, very few email addresses are kept in secrecy. So there is tons of people who know my or your email address which means anyone could use it to register anywhere.

I had multiple occasions recently when I thought that email verification could come in very handy. Doing some research for the best approach I found some useful comments on general appraoches to take but did not find a somehow straight forward guide. So I just started developing a solution for myself and thought: Why not share it?!

Why verify users' email addresses

I'm sure there is tons of reasons to verify your users' email addresses but there are two very basic ones that I found important when developing web applications recently:

  1. Make sure the email actually exists
  2. Make sure the person registering actually owns the email address

There are many different useful implications in terms of e.g. marketing, sales and legal, but let's just acknowledge that there are valid reasons to conduct email verification.

Prerequisites

I don't want to dive too deep into technology and framework dependent code. In my case I used Vue front-end application and node.js/Express on the backend (GitHub). I'll also try explaining the approach as high level as possible. However, a few things are needed to set-up the system:

  • front-end for user interaction (I used Vue)
  • a server on the backend (I'll refer to node.js/Express where necessary)
  • a database that the server is able to communicate with (I used mongoDB with mongoose)
  • an email service connected to and usable by your server (I used nodemailer with an email service provider I already use)

The register and login functionality should be set up already. This is where we get started.

Step by Step Guide

Step 1

Assign a status property to your user model in the database. In my case where I am using mongoDB with mongoose and a 'users' collection:

status: {
        type: String,
        default: "pending",
    },

Anyone who registers will get a default status of pending until the user's email address is verified.

Step 2

When a user registers, create a secret code in your database which is connected to the user through e.g. the user's email address and is used to verify the email address later on. In my case I set up a 'codes' collection in the database and a mongoose schema as follows:

const secretCode = new Schema({
    email: {
        type: String,
        required: true,
    },
    code: {
        type: String,
        required: true,
    },
    dateCreated: {
        type: Date,
        default: Date.now(),
        expires: 600,
    },
});

Note: The entry expires after 600 seconds (10 minutes) in order to limit the lifetime of the code.

Step 3

At the end of the server side registration process where you add the user to your database and built the secret code from (2.) send an email to the user's email address with an activation link (plus any additional information you want to provide in certain cases).

The activation link should point to a server's endpoint and include a part that can be uniquely connected to the user account (e.g. user's ID from your database) and the secret code from (2.).
In my case the link structure looks like this:

url: `${baseUrl}/api/auth/verification/verify-account/${user._id}/${secretCode}`

Note: As the secret code produced in (2.) expires after 10 minutes, you should provide a possibility for the user to resend an activation link at a later point. You could implement a button on the front end which appears as long as the user's status: "pending" and hits a specified endpoint on your server taking care of the code generation and email sending.

Step 4

Redirect the user to a verification page on the front-end where they are informed to check their email inbox for the activation link.

Note: That could be a good place to put the mentioned 'Resend Activation Link' button. As long as the user's status: pending they should be redirected to this page and should not have access to the private area of your application. It does not matter whether they register or login at that moment.

Step 5

On your server you need to set up an endpoint for the activation link.
The route could look like this:

"/api/auth/verification/verify-account/:userId/:secretCode"

where you (in case of node.js/Express) extract the parameters like this:

const { userId, secretCode } = req.params;

Now the only thing you need to do is:

  1. Get the email address connected to the userId from your database
  2. Check if there is a secret code in your database that is connected to the user's email address
  3. Update the user's status to status: "active"

Step 6

As the user's status has been updated successfully you can redirect the user to the protected private area of your application.

And finished you are! Of course this is only a very high level description and there is a lot more going on in terms of routing and route protection in the background.

You can view my full example on GitHub and even use it as a template if you wish.

Wrap Up

To conclude, here a short wrap up of the steps as laid out:

  1. Set up an initial user's status of "pending"
  2. Create a secret code connected to the user when registering
  3. Send email to user including an activation link with user specific information (e.g. user ID) and the secret code
  4. Redirect user to verification page
  5. Set up server endpoint that is hit by the activation link, extracts and verifies the data provided through the link and updates the user's status to "active"

Discussion

markdown guide