Node.js + MongoDB: Authentication and Authorization using JWT

Tram Ho

I. Introduction

In most back-end application systems, authentication and user authorization are required. For example, when creating a website, of course you need to build the registration feature, login, decentralize admin, mod, member … There are some techniques to help you build this feature, for example: using Sessions , or newer is JWT.

Through this article, we will together build an example Node.js + MongoDB application supporting User Authentication (registration, login) and Authorization by JSONWebToken (JWT).

II. Differences “Authentication” and “Authorization”

Do these two terms sound the same? However, they are a bit different. I will not go into detail about their performance. In this section, I just want to highlight the features so that you can distinguish Authentication and Authorization.

1.1. Authentication

Authentication is the process in which the system checks and determines the identity of a user or another system that is accessing the current system.

Understandably, the Authentication process finds an answer to the question: “Who are you?”

The Authentication process is very popular, most CMS related to content management and user interaction do. Currently, authentication is mainly based on two information: username and password.

1.2. Authorization

Similarly, the authorization process answers the question: “What are you allowed to do?”.

Technically, authorization is usually done after authentication is over. That is, after knowing who you are, the next step determines what you are allowed to do in the system.

III. Token Based Authentication

Compared to Session-based authentication, you need to store the Session in Cookies. The biggest advantage of Token-base authentication is to store JSON Web Token (JWT) on the client such as: Local Storage on Browser, Keychain in iOS app or SharedPreferences in Android application, etc.

Therefore, we do not need to build a satellite project or an additional authentication module to support non-browser applications (eg Android mobile applications, iOS …)

Below is a diagram of JWT’s activity flow.

There are 3 important components of JWT:

  • Header
  • Payload
  • Signature

They are combined together to form a standard structure:

Client application often attaches JWTs to the header with the Bearer prefix:

Or just add an x-access-token field in the header

IV. Practice Node.js & MongoDB User Authentication

After learning about the theory, now is the time to get started. We will build a Node.js + Express application with user authentication + authorization, in which:

  • Users can register a new account or login if they already have an account.
  • Decentralize user accounts by role (admin, moderator, user). For each role, users have different rights to access resources.

Here is a list of the essential APIs:

V. Flow program for Signup & Login feature

Below is a diagram that describes the process a Node.js application will perform for the Authentication (User Registration, User Login) and Authorization features.

A valid JWT to access system resources must have an x-access-token field in the HTTP Header.

BECAUSE. Node.js Express Architecture for Authentication & Authorization

The figure below shows an overview of the application architecture using Node.js + Express for authentication & authorization.

Through Express, HTTP requests that are valid and correct with the designated route (see Table 3.1 for the list of APIs used in the app) will be checked by CORS Middleware before entering the Security layer.

Security layer includes:

  • JWT Authentication Middleware: is responsible for verifying SignUp, token chain.
  • Authorization Middleware: Checks the role of the login user with the information stored in the database.

If there is any error during the whole process above, it will immediately respond to the client as an HTTP response (error code).

The techniques used for this example (version may differ in the future but should not be a problem):

  • Express 4.17.1
  • bcryptjs 2.4.3
  • jsonwebtoken 8.5.1
  • mongoose 5.9.1
  • MongoDB

For your development environment, you will need to install the following software in advance:

  • Nodejs: Detailed instruction to install Node + Npm
  • MongoDB: this is the database management software.
  • Download and install Visual code or Sublime Text 3: to write code faster

VII. Project directory structure

Below is the project’s source directory structure in this article:

VIII. Create a NodeJS project

To get started, we need to create a new NodeJS project. In this section, I will not guide again, you can refer to how to do details here: Create a NodeJS project

When creating a new project, you need to create the necessary libraries: express, cors, body-parser, mongoose, jsonwebtoken, and bcryptjs.

Using npm to install them, type the following command:

The package.json content of the project is as follows:

IX. Set up Express web server

In the root of the project, create a server.js file with the following content:

I will explain a little bit about the code in server.js:

  • We import Express to create REST API
  • The body-parser library is used to parse requests into the body object.
  • Import cors library providing Express middleware used to enable CORS feature

Finally, you can test the application with the command: npm start

Access the browser from the path: http: // localhost: 8080 /

X. Configure MongoDB connection

In your app directory, create a new directory and name it config. This directory will contain all the files related to the application configuration.

In the config directory, create the db.config.js file to add the MongoDB database setting information to the application:

XI. Mongoose Model definition

In the model directory, create the User and Role model as follows:

models / role.model.js

models / user.model.js

These Mongoose Models will represent the collection created in MongoDB. When you run the program, Mongoose will automatically create two collections named: users and roles.

Once you have declared it, you do not need to create CRUD (database read and write) functions because Mongoose already supports it. For example:

  • Create a new User: with function object.save ()
  • Find a User by Id: Use User.findById (id)
  • Find User by email: User.findOne ({email:…})
  • Finds all roles: Role.find ({…})

These functions will be used by us in Controllers. Just calm down.

XII. Initialize Mongoose

Now we create app / models / index.js with the following content:

Reopen the server.js file to add the following code to open the Mongoose connection to the MongoDB database.

The initial () function allows us to add 3 roles data to the database, if it exists in the database, then ignore it.

XIII. Configure Auth Key

The jsonwebtoken functions such as: verify (), sign () will need a secret key to encode or decode the token string.

In the app / config directory, create auth.config.js with the following content:

In it, you can create any banana secret for your own.

XIV. Create middleware functions

In order to verify an action in SignUp, we need to do 2 things:

Check if the username and email are duplicated in DB or not? Check if the registered role is valid or not? middlewares / verifySignUp.js

To handle Authentication & Authorization, we need to create the following functions:

  • Check the token is valid or not? We can get the token information in the x-access-token field of the HTTP Header, then pass it to the verify () function for processing.
  • Check whether the registered role has a role or is empty?

middlewares / authJwt.js

Finally, create the index.js file in the middlewares directory to export them:

XV. Create Controllers

We will in turn create controllers for 2 parts: Authentication and Authorization.

Controller for Authentication With this section, we have two main jobs for the authentication feature:

  • Register: create a new user and save it in the database (default role is User if not specified before registration).
  • Login: the login process consists of 4 steps:
    • Find username in the database,
    • If username exists, compare the password with the password in the usage database. If the password matches, create a token with jsonwebtoken and then return the client with User information with access-Token The principle is that, now the source code:

controllers / auth.controller.js

Controller for Authorization We have 4 main APIs for authorization:

  • / api / test / all
  • / api / test / user
  • / api / test / mod
  • / api / test / admin

controllers / user.controller.js

In the next section, we will associate these controllers with middleware. If everyone feels tired, then rest, make a cup of coffee to get strength to continue.

XVI. Routes definition

When a client sends a request to a web server using HTTP (GET, POST, PUT, DELETE), we need to define and determine how the server receives and responds. This is exactly the use of routes.

We divide the routes into two groups: Authentication and Authorization

Authentication:

  • POST / api / auth / signup
  • POST / api / auth / signin
  • routes / auth.routes.js