How to Authenticate From Scratch Using Node.JS and MongoDB

Understand the basics of how auth works, and make a basic system without passport or its alternatives.

Agrim Chopra
Mar 27 · 8 min read
Photo by AltumCode on Unsplash

There are a large number of libraries available to enable authentication in every framework and database system. And while some of those are fully capable of catering to any general authentication need, there can be situations in which we may want an even higher level of control over how our users sign in to our product and in such a case, we would like to do everything from scratch.

However, before we start, note that if your need is a basic one, it is much better to go for a library like passport.JS, which is constantly updated by people very knowledgeable in the field of web security. Following this article will help you understand the basics, but making your site safe from attacks is a different topic altogether.

Some Important Points

  1. It is assumed that you do possess basic knowledge of Node.JS and MongoDB. While I will be explaining everything as we go along, it is difficult to introduce Node and authentication in just 1 article.

That being said, let us move on to the aim of this article. However, before we jump to the code, let’s divide our problem into smaller subproblems which we can solve one by one, eventually solving everything.

  1. Registering a new user
  2. Logging a user in
  3. Logging a user out.
  4. Keeping the user logged in for a session.

The first 3 points here are fairly straight forward and their meaning does not require much of an explanation. However, to understand why we need the fourth point, I need you to think of when you log in to Facebook on your laptop. How does it work? Do you get logged out every time you refresh your page or move to some other page inside Facebook itself? Do you have to login again if you open Facebook in a new tab? No. That is what that point will help us do. It will help the browser remember if we logged in, and use that until the session expires.

The Code

0. Setting up the project and making a database where the user data will be stored.

Of course, we will need a database where the login details are used. Let us do that first.

Setting up the project and database

For the project setup, follow the below steps:

  1. Open Terminal on your system.
  2. Move to the directory where you want to create the project.
  3. Run mkdir authDemo; cd authDemo. This creates a directory named ‘authDemo’ here and moves us into it.
  4. Run npm init -y. This creates the mandatory package.json file in the directory, required for node.
  5. Run npm i -S mongoose express bcrypt express-session. All the names after the -S are just packages that we need for our project. We are installing them.
  6. Run touch app.js. This creates an app.js file where we will have all our code. Open this file in your favourite code editor.

Now our project has been set up. We can start setting up our database. Inside the app.js file, write the following code:

Let’s understand what we have done:

  1. Require statements: line 1 and 2 simply include the packages we will need into our file.
  2. mongoose.connect : This connects us to our database, which is currently named ‘myapp’.
  3. Schema: In mongo, we need to define a structure as to how the entries in our collection will look. This is the schema. Here, for a user, we have said that we will have ausername, which will be a string, andhashedPw, which will be a string. Both these fields are necessary, i.e. cannot be empty. Why we are using hashedPw(hashed password) instead of just password will be clear later in the article.
  4. Model: In MongoDB, we use models to do all the work through code. Hence, we make that model in line 15, and store it in User.
  5. App.listen: This line tells our code to run the server on port 3000 when we run the node file by running node app.js on the terminal. Due to this, now we’ll be able to access the routes we are making on localhost:3000/

Okay, so now our database is also set up. Let’s move on to Step 1, i.e. Register.

Register A New User

Let us go over the changed lines here:

  1. Line 3: We require a new module, bcrypt. This will be the hashing algorithm we will use. We’ll discuss more about hashing, but let’s understand all the other points first.
  2. Lines 22–30 : This is our POST route for registering a user. Here, we are hardcoding the values of username and password, which you would usually get from a form. Next, we generate the hashed password, which we come to later. Once we have both these things, we create a user with these details and add it to our database. We now return the user we just created as a response from the route.

Hashing

Coming back to what it is, hashing is just one-way encryption of some text. What does that mean? It means it converts a set of characters we give to it into a very long and random string, which has 2 main characteristics you need to know:

  1. The same string is always converted to the same random string.
  2. The original string cannot be re-traced from the hashed string.

It is common practice to store passwords in a hashed form, and absolutely no good company would store passwords as just plain text. If you wish to learn more about hashing, you can check here.

That being said, now we can safely move to the next step, i.e. login.

Log A User In

If you see here, only lines 33–46 have been added. Initially, we are taking the hardcoded values of username and password, which are same as what we took in the register route. We are then finding a user with the said username from our database, and store it inside user. Next, we compare the password of the given user with the password we have received. Remember that the password we have stored is a hashed version, and hence we cannot directly compare the values of the 2 strings. We will use bcrypt.compare(), which is the inbuilt function for comparison in the library.

Note: Do not attempt to manually hash the password you have received and then compare strings, that does not work. To understand why, please read the concept of salt from the link above.

Next, we receive true or false inside the matchstatus variable, and that tells us if the password was correct or not. We do our actions according to it.

Note: Currently, we are just doing console.log or res.send. This is not actually logging us in. This is just the code to check if the details are right or wrong. The actual logging in part actually occurs below, when we discuss sessions. We will update this route when that happens.

Now that we have completed the login route for now, let us move to sessions. Note we are covering sessions before logout as logout will not make any sense without it.

Add Sessions To The Site

As a basic understanding, you can understand it as the memory the browser is keeping of our browsing. In general, HTTP requests do not have memory. Hence, even if you log in correctly, there is no way to let the rest of the site know that you are successfully logged in. This is where sessions would come in in auth. As a session memory is stored by the browser, it doesn't matter which URL we are going to inside the site, the data inside the session will always be there.

So our approach for logging someone in could be this: We create a variable named user inside the session(of course you can have any variable name). When a user enters the correct details for authentication, we can set the user variable inside the session to be the user details. If not logged in, it remains null. So at any point of time, if we need to check if the user is logged in, we just check if this variable is null or has a valid value.

Let’s see the code for this now:

Though the explanation made it look like we would be doing something very very complex, it is actually pretty simple to code. Let’s see the additions of the above code :

  1. Lines 4 –10: We require and configure express-session, which is the library we are using to create sessions and maintain them. These lines will configure the session in the browser, and make it extremely easy for us to access it, as we will see now.
  2. Line 47: req.session.user = user; : As I mentioned above we set a variable called user inside the session(which we access by req.session) to the user we just logged in.

This successfully logs us in and we can now later access the details of the logged-in user, no matter what page we are on.

Let’s now see the final and easiest route of all, the logout route.

Log A User Out

Here, we have just added the logout route in lines 55–58. We set req.session.user to null, and then return a response.

Wrapping Up

Geek Culture

Proud to geek out. Follow to join our +500K monthly readers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store