Securing your Node js api with JSON Web Token

Securing your Node js api with JSON Web Token

Introduction

Nowadays REST ( Representational state transfer) has become the most used style in web architecture due to their simple syntax and flexibility . REST allows users to make their apps extensible, the fact that a client from different frontend platforms can perform requests to the server using http protocol in a simple way and exchange data which could be encoded in JSON or XML format.

Now with all the features that comes up with Restful architecture it still have some problems specially with their security .

 From the many security approaches that are used to secure Restful api's is token based authentication

So what is token based authentication ?

let's make this easy :))

The general concept behind a token-based authentication system is simple.

Allow users to use their username and password in order to obtain a token which allows them to access a specific resource without using every time their natural credentials.

Once their token has been obtained, the user can use that token to access a specific resource in a server for a time period to the remote site.

How it works ??

well the process of using jwt is composed of 6 steps

1- authenticate using credentials

2- once authentication is granted the server generate a random string which contains the json web token

3- return the token to the client side

4- storing the token in the client side

5- sending the token with every single http request from the client to the server

6- the server check whether the token is valid or not and grant access to the specified resource

What we are going to build ?

well in this article we are going to build an API with Node js and Express.js and we will test it with postman so let's get started :))

first let's take a look at our project structure

-/configurations
             ->/config.js

-package.json

-index.js

now that our project is dived and ready to go let's install our packages.

open your command line under your project directory and write this command

npm install --save  express body-parser morgan jsonwebtoken 

so let's explain the packages that we have installed

Express : the famous node js framework

body-parser: allow us to get the data from the body of the requests

morgan : logs the requests in the console

jsonwebtoken : the package that allows us to generate jwt and build our middleware to check whether the token is valid or not .

Now let's go the config.js

config.js

well accually this file is used to setup some configurations that most users need to do in order to better organise their projects.

They can setup configuration for databases or for other purposes , in our case we are going to use this file to setup our secret which will be used when creating our jwt so the file should look like this

module.exports = {

    secret : "heymynameismohamedaymen"
}


Now let's go to our index.js which is the most important file in our app .

index.js

const express = require('express'),
bodyParser = require('body-parser'),
morgan      = require('morgan'),
jwt    = require('jsonwebtoken'),
config = require('./configurations/config'),
app = express(); 

//set secret
app.set('Secret', config.secret);

// use morgan to log requests to the console
app.use(morgan('dev'));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// parse application/json
app.use(bodyParser.json());

app.listen(3000,()=>{

 console.log('server is running on port 3000') 

});
app.get('/', function(req, res) {
    res.send('Hello world  app is running on https://localhost:3000/');
});


to check if everything is ok go to the command line and run this command

node index.js 

open your browser on https://localhost:3000/

well everything looks fine !!

we can see also that the request is logged in our console thanks to morgan package

Setting up the authentication system

Now comes the best part of our app :)) .

Well in this app we are not really going to work with real models which are stored in database but we are going to setup a static login and password to check whether the user exists or not ,because what we want to focus on in this article is the usage of JWT, so simply you can change the code that we are about to write .

so in our index.js let's create the authenticate route

here we choose aymen as a username and 123 as a password

app.post('/authenticate',(req,res)=>{

    if(req.body.username==="aymen"){

        if(req.body.password===123){
             //if eveything is okey let's create our token 
         
        const payload = {

            check:  true
  
          };

          var token = jwt.sign(payload, app.get('Secret'), {
                expiresIn: 1440 // expires in 24 hours
 
          });
  
          
          res.json({
            message: 'authentication done ',
            token: token
          });
       
        }else{
            res.json({message:"please check your password !"})
        }

    }else{
       
        res.json({message:"user not found !"})

    }

})

now that the route is build we can get back our token .. so let's make a test with postman

now that we have the token, as a client we have first to store that token somehow and there are many tools to do that , for exemple if we are using our browsers we can use localstorage or if we are using android to create a mobile app we can use sharedpreferences

Setting up the middleware

For the moment we have our token and we can make http requests to the server , but we must also build our middleware that will handle every http request , search for the token and check if it's valide or not .

But before creating the middleware we must create the routes that will be protected with it , so in our index.js the protected routes should look like this

const  ProtectedRoutes = express.Router(); 

app.use('/api', ProtectedRoutes);

Now every route under /api will be a protected route by the middleware and to get access to the resource that uses /api as a parent route we have to provide the right token for it .

To send the token to the server along side with some data we usually store the token in the header of every request after that the middleware will handle the http request and extract the token from the header .

so in our index.js let's write the code that will do that

ProtectedRoutes.use((req, res, next) =>{

     
    // check header for the token
    var token = req.headers['access-token'];
  
    // decode token
    if (token) {
  
      // verifies secret and checks if the token is expired
      jwt.verify(token, app.get('Secret'), (err, decoded) =>{      
        if (err) {
          return res.json({ message: 'invalid token' });    
        } else {
          // if everything is good, save to request for use in other routes
          req.decoded = decoded;    
          next();
        }
      });
  
    } else {
  
      // if there is no token  
     
      res.send({ 
    
          message: 'No token provided.' 
      });
  
    }
  });

To check if our middleware works or not we are going to create another route in which we are going to return an array of products and we are going to set this route under /api using ProtectedRoutes, after that we will make a GET request to get the data back .

first let's create the route


ProtectedRoutes.get('/getAllProducts',(req,res)=>{
 let products = [
     {
         id: 1,
         name:"cheese"
     },
     {
        id: 2,
        name:"carottes"
    }
 ]

 res.json(products)

})

now let's try to get the list of products without providing the token and see what happens

this time the middleware did not return the data because we did not provide the token or in other word the api did not recognize us and thought that we are the bad guys that want to grab some informations .

so now using postman we are going to put the token in the header of our request and let's perform another request

everthing looks great we get the data back ;)).

Conclusion

In this exemple we had a great look at the usage of JWT and their importance for the security of the Restful Api's , note that this is not the only approach for the security of node js apps but there are a lot of tools that could be very usefull .

we hope that this look has given a better understunding about how the tokens are created , how the routes are protected and how all of this if managed inside a node js app .






Mohamed Foudhaili

Cyber Security Specialist | Security Program Manager @Yogosha

6 年

Great guide buddy ! keep it up !

Matthew Quade

Software Engineering Manager - Synchrony

6 年

Just worked through this thanks for sharing!

Atharva Pandey

Co-Founder and CTO | Web3 & Decentralized Applications, Strategic Product Development

6 年

well i have been struggling a lot lately to decide where to actually store jwt cookies does not feel right and then local storage or session storage seem to be over visible to the end user ... there should be a good way to do this some other way

要查看或添加评论,请登录

社区洞察

其他会员也浏览了