Raoul Vandevelde
Posted on June 18, 2023
Written by Raoul Vandevelde
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 middle-horses - some developer
Let's first go into something called the JWT or JSON Web Tokens, 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:
JWT_ACCESS_TOKEN = YRskPK2K5CoW0lOp4Fl9
Having done this we will install the package needed to work with JWT.
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:
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
dotenv.config();
For the admin authentication we will check two things:
- Is the user logged in?
- 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:
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?
The function defined takes three parameters into account:
req
,res
andnext
. 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:
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) withprocess.env.JWT_ACCESS_TOKEN
.If this verification succeeds, it checks if the decoded payload has
is_admin
equal to 1 (make sure youris_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 thereq.user
if the user is indeed an admin and thenext()
function is called to proceed to the next middleware or route handler.
} 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 acatch(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:
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 will get you a long way!
- Test route without being logged in:
- Log in with an admin account:
- Test it again
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!
Posted on June 18, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.