logo

Easy Authentication with Redis

Kenneth Jimmy

8/12/2022

You are a developer and have probably built some applications for some users. Your users are required to sign up before they can access some resources on your application. To complete the signup, they must also verify their email. While some users are entirely ok with that extra step, most don't find it pleasant even though they know that they have to do it. Why? It is too manual. What if there was a better way of verifying the user's email without making it too explicit? Well, let me introduce you to the Magic Link authentication model. You may have heard of it already or even used it somewhere before. When signing up, this is how it works from users' perspective:

  • They enter their email address
  • A link is sent to that email address
  • They go to their inbox and open the link (This is where the verification is applied subtly)
  • They are redirected to a signup page where they will enter the rest of their details like name, password, phone, etc.
  • They sign up and are immediately signed in too

Easy-peasy! No one has to know that they have to verify their email - they simply do that without noticing it. This is why the magic-link model has been intuitively embraced in modern authentication systems. But there's a lot going on behind the scenes during this process. That is where this tutorial is focused on.

There are some ways to implement this concept on the backend and the choice is yours. But you don't have to choose less efficient ones. Think about it. If you wanted to implement this with Express.js, how would you do it? Maybe you would create an endpoint (endpoint 1) that implements the following algorithm:

  • Collect the email from the request body
  • Generate a token using the node.js built-in crypto package
  • Store the email and token along with an expiration time in a separate (from your User) table in a database
  • Inject the token into a URL (that matches a page on the frontend) and send it to the given email address

Then, another endpoint (endpoint 2, usually the signup route) that does the following: Check if a token is provided in the request object

  • Collect the user's details including and especially the email address
  • Try to pull the record with the given token from the database from the "special" table
  • If the record does not exist, return a forbidden error
  • If the record exists but the expiration time has expired, return a bad request error
  • If the record exists and the expiration time is still valid, create a new user with the given details

Let's think about this approach for a moment. Do you think it's effective? Well, everything looks ideal except for step 3 of endpoint 1. Here's why I think so:

  • Storing the token in a database is meaningless because it is just preliminary data that will become useless afterward.
  • Your database will be bloated with junkie data. And you may argue that you can apply the 7th step in endpoint 2 to delete the record afterward but still, using the database for this is less efficient and not ideal for production in my opinion. I am sure you can think of other downsides to this approach.

A better approach would be to use JWT. Using JWT will handle steps 2 and 3 of endpoint 1. Then, step 3 of endpoint 2 would be geared towards validating the token with JWT instead of the database. Still, this is not the best solution. The reason is that using JWT is overkill for this simple problem.

A much better solution would be using RedisJSON.

RedisJSON is a high-performance NoSQL document store that provides native APIs to ingest, index, query, and run full-text search on JSON documents both on-premises and as a managed service in the cloud. This means that you can use RedisJSON in-memory [key-value] data structure store as a database and cache. You can learn more about it here. Let me show you how Redis can eradicate the inefficiency of step 3 of endpoint 1.

The Project

For this tutorial, I created a project that we will use throughout. It is a very simple Express application that exposes three RESTful API endpoints - /users, /users/magic_link, and /users/signup. You can clone or download the source code here. It is a dockerized application...

~Read more on LinkendIn here~