Securing an API — Authentication and Authorisation using Passport-JWT strategy
By: Christiana Okere
Tags: Hashing And Salting, Passportjs, Jwt Auth, Authentication, Authorisation

Hey Nerds!!!

In my last post, we learnt how to build an API. In this post, we would learn how to secure the API that we built. We would be using the same folder we used in the previous post, so ensure that you followed and understood the previous post before coming onboard this one ;-)

Let’s begin by understanding why it is important to secure our API in the first place.

The server may have resources or files that should be protected so that only the right user(s) can access them. Hence we need to have a trusted computing base that ensures that every request that comes for a resource is monitored.

Before granting a user access to a resource, two questions must be answered: the first is — who is the request coming from? To answer this question, we use a process called Authentication — this process helps to know the identity of the source, and to verify that the user is who he/she claims to be.

Once we have established the source of a request, the second question is — does the source of the request (alias User) have the permission necessary to use/access the resource he/she is seeking? To answer this question, we use a process called Authorisation.

It is important to emphasise that authentication does not determine what tasks the user can do or what files the user can access. Authentication only identifies and verifies the user.

Once authentication and authorisation is done, then we allow the user access to the resource.

So, lets get to the nitty-gritty of this entire process and see how to set up a secured system.

First, recall that in our last post, we registered a user, and her details were stored in the database for future comparisons (like when he/she returns to the site to login). To ensure security of the user and organisation, passwords must never be stored in plain-text format. Hence, we use two encryption processes — hashing and salting — to make passwords more unique and secure its storage.

The first step to achieving this is to install bcrypt using the command line:

npm install bcrypt --save

Bcrypt is saved as a dependency in the package.json file.

Next, require the bcrypt module in the userController file:

const connection = require(‘../models’);

const bcrypt = require(‘bcrypt’);

Next, has hand salt the password as done below:

const saltRounds = 10;

const salt = bcrypt.genSaltSync(saltRounds);

const hash = bcrypt.hashSync(req.body.password, salt);

Compare the two images below and observe the difference between a secured and an unsecured user password:

Password in plain-text format

hashed and salted password

Now that our password is more secure, lets set up authentication and authorisation.

The entire process begins when a user tries to access a site or information. This can be done in several ways (login, voice recognition, retina scans etc.) depending on how the system is built.

In this guide, we would use a login session to illustrate authentication and authorisation.

Begin by creating a post route (users/login) in the user route:

router.post(‘/login’, userController.login);

Next, install Passport — an authentication middleware for Node.js. Passport authentication identifies a user using his or her e-mail address and a password. Passport uses several methods/strategies for authentication like Oauth, JWT e.t.c.

We would use the JSON Web Token (JWT strategy) in this guide.

First, install passport and passport-jwt using the command lines:

npm install passport passport

npm install passport-jwt

These are saved as dependencies in the package.json file.

Next, hook passport up to your Express app by typing the following in the app.js file:

const passport = require (‘passport’) app.use(passport.initialize());

require(‘./config/passport’)(passport);

Next, create a passport.js file in the config folder and input the following:

const JwtStrategy = require(‘passport-jwt’).Strategy;

const ExtractJwt = require(‘passport-jwt’).ExtractJwt;

const models = require(‘../models’); const Users = models.User; const jwtOptions = {} jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); jwtOptions.secretOrKey = ‘myVerySecret’; module.exports = passport => { passport.use(new JwtStrategy( jwtOptions,(jwt_payload,done) => { Users.findOne({ where:{ id:jwt_payload.id } }).then(user => {console.log(user); console.log(jwt_payload); if(user){return done(null, user)} return done (null, false); }).catch(err => console.log(err)); } )) }

Next, go to the userController.js file and require the dependencies:

const jwt = require(‘jsonwebtoken’);

const passport = require(‘passport’);

Next, declare a constant “data”, which refers to the user login details and another constant password which refers to the hashed password stored in the database.

const data = req.body;

data.password = hash;

Next, set up the login controller as follows:

const login = async (req, res)=>{

const email = req.body.email;

const password = req.body.password; const user = await connection.User.findOne({

where:{

email : email

}

});

Next, declare a constant “checkPassword” that compares the user’s inputted password during login (password) to the hashed password saved in the database (user.password)

const checkPassword = bcrypt.compareSync(password, user.password);

if (!checkPassword){

return res.json(“your password is incorrect”);

} else {

const payload = {

id:user.id,

} const token = jwt.sign(payload, ‘myVerySecret’) res.json({

“token” : token,

“msg” : “login successfull”,

“user” : showuser,

“statusCode” : 200

});

Also set up a “getOneUser” route and controller. This would enable us test the authorisation process.

The getOneUser route set-up:

router.get(‘/user’, passport.authenticate(“jwt”,{session:false}), userController.getOneUser);

The getOneUser controller set-up:

const getOneUser = async (req, res)=>{

const data = await connection.User.findOne({where: {id:req.user.id}}); res.json(data);

}

Do not forget to export all functions at the end

module.exports = {

register,

login,

getOneUser

}

Next, lets test our authentication and authorisation process using the Postman app.

First register a new user:

Register

Next, login and copy the token generated (the token is generated signifying that the user has been authenticated):

Login and copy token generated

Finally, switch to Headers and paste the token in Bearer. The token gives you authorisation to the users/user route as shown below:

Token gives you authorisation to the users/user route

Thanks for reading!!!

Don’t forget to clap if you learnt a thing or two :-)