Auth, Auth, Auth?
Tags: webdev, node, api, security
Published: 2023-06-18 19:43:34

##### Written by [Raoul Vandevelde](https://github.com/RalloField)

---

### Middlewares in Node.JS

During my training at **BeCode** and a dive into the world of building **API**'s with **Express**, it was time to build an API ourselves.
The exercise consisted of making a webshop API of which we could choose the subject.
Ofcourse, this came with a lot of questions like, how would a user experience this in their browser? Would they be able to add, change and delete things from the database at will?

That's something an e-shop owner would not want, right? 
Our goal, after having made all the necessary controllers and database connections:

- Make **authentication** and **authorization** middlewares so only those who are authorized by the admin (in this case, the shop owner), have access to the specified functions in the controllers.

### Setup and context

A bike-shop owner has asked you to create an API in which he can add his collection of bikes, to sell on his website.

Let's just asume you have created your file-structure and are ready to create some middlewares!
> Hells yea! 



![hold_your_horses gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d8bructfccral0d227p.gif)

> Hold your middle-horses - some developer 

Let's first go into something called the [JWT or JSON Web Tokens](https://jwt.io/introduction), which we will need to securely transmit our information to authenticate. Be sure to read up on it before continuing. 

We define our JWT_ACCESS_TOKEN in our .env file where we will assign to it a digital key.

For Example:

```javascript
JWT_ACCESS_TOKEN = YRskPK2K5CoW0lOp4Fl9
```

Having done this we will install the package needed to work with JWT.

```terminal
npm install jsonwebtoken
```

___

### Ready? Authenticate, Authorize, Set. Go!

Let's get to work!
Make a folder in your structure which will contain all your middlewares.
No need to think deeply about the name, just call it 'Middlewares'.

Create a file named `admin_authentication.middleware.js` in the new folder you just created, and require at the top the following packages:

```javascript
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
dotenv.config();
```
For the admin authentication we will check two things:

1. Is the user logged in?
2. If so, is the logged in user an admin?

Let's get into the first point.

#### Logged in?

We will check if the user accessing the page is logged in or not.
This first part will look something like this:

```javascript
const authenticateAdmin = (req, res, next) => {
    // Extract the access token from the request cookie
    const accessToken = req.cookies['webshop.process'];
    console.log(accessToken);

    if (!accessToken) {
        // If access token is not present, user is not authenticated
        return res.status(401).json({ message: 'Unauthorized' });
    }
```

> Let's break down the code shall we?


![break_it_down](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6i2prq5pj2s4sdvuand.gif)

* The function defined takes three parameters into account: `req` , `res` and `next`. Next is used to call the next middleware or route handles when the middleware has passed.

* We extract the access token from the cookie with `req.cookies['webshop.process']`.

> Note: the `['webshop.process']` is specific to what we are doing here and should be updated to the name you used in your login- or sessionscontroller when signing the cookie.

* In the if statement we check if the access token is present or not.

Not, would mean they are not logged in and as such not authenticated to utilize the functionality being called in the routes.

* We respond with a `401 Unauthorized` message.

If they are indeed logged in, we will continue with the next part of the function.


#### Are they admin?

After having checked if they are logged in, let's check if they are an admin or not.

We consider the following code:

```javascript
try {
// Verify the access token
 const decoded = jwt.verify(accessToken, process.env.JWT_ACCESS_TOKEN);
  console.log(decoded);
  console.log(decoded.is_admin);
// Check if the user is an admin
  if (decoded.is_admin !== 1) {
     return res.status(403).json({ message: 'Forbidden' });}
        req.user = {
            is_admin: decoded.is_admin};
// Attach the decoded user data to the request object
next(); 
// Proceed to the next middleware or route handler
```

* If the access token is indeed present, the function will verify it with `jwt.verify()` -> this will pass the token and the JWT digital secret (from the .env file) with `process.env.JWT_ACCESS_TOKEN`.

* If this verification succeeds, it checks if the decoded payload has `is_admin` equal to 1 (make sure your `is_admin` column is a boolean type, where 1 makes sure it is an admin).

If this is not the case, the function will respond with a `403 Forbidden` status and a JSON message if needed.

* Lastly, the `is_admin` property is being attached to the `req.user` if the user is indeed an admin and the `next()` function is called to proceed to the next middleware or route handler.

```javascript
} catch (err) {
        // If access token verification fails, user is not authenticated
        return res.status(401).json({ message: 'Unauthorized' });
    }
```

* Because we used `try` in our function we should also use a `catch(err)` to make sure something is returned when the verification fails

---

### Final touches before testing

* Make sure that you export the function by putting this line below on your page:

`module.exports = authenticateAdmin`

* Access your routes file where you want to use the middleware and require it at the top:

`const authenticateAdmin = require('../../MIDDLEWARES/admin_authentication.middleware');
`
Depending on your filestructure this path will vary.

* Add the middleware(s) in the chronological order:

```javascript
router
.route('/admins')
.get(authenticateAdmin,adminController.getAdmins)
```

This route will first check the authenticateAdmin middleware, before it executes the function specified behind it coming from the controller. In this case the admin must first be logged in and authorized before it can see a list of all the admins in the database.

---

### The Test

To test our middleware but also to test your routes and methods in your controller, we will use a program called Postman. Postman is a handy little tool that will help us check if the middleware we just made really works.
> *Pro-Tip: To read more about how to use Postman in your project, [this article](https://dev.to/biceschembri/how-i-used-postman-to-test-my-express-api-1bk0) will get you a long way!*

* Test route without being logged in:


![Forbidden_access](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dme0wkgwqoepxjn85tsg.png)

* Log in with an admin account:


![login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lq2s2e4vghmdhktg8gcs.png)

* Test it again


![authenticated](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ju0zifhmn5bo27sfhz98.png)

As you can see, the middleware works for this route. But you can now apply it also for other routes where only an admin would have access to.

---

#### Thanks for reading!

I sincerely hope this has helped you out. I will keep updating this article if I find more during my middlewaring during my journey in web-development.


Cheers!


![youshallnotpass](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivvhs4ujvkfa5yvtot57.gif)