What is JSON Web Token (JWT)?

JWT is a standard that allows us to transfer data securely between client and server. The information passed can be trusted because it is digitally signed.

Advantages of JWT

  1. In a multi-server environment where a load balancer picks server, we don’t have to worry about which server is being picked as JWT are not stored anywhere
  2. No need to store ‘n’ records in database for ‘n’ logged in users
  3. Easy to use and scale
  4. Built in expiration facility
  5. Prevents Cross Site Request Forgery (CSRF)
  6. Most useful with mobiles

JWT Structure

JWT consists of three parts separated by dot (.)

header.payload.signature

Header

Header consists of two parts: Hashing algorithm and Type of token, which is JWT

{
    "alg": "HS256",
    "typ": "JWT"
}

Payload

This part contains statements called Claims that contains data about an entity like user.

Signature

To create the signature, we take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

To learn more about JWT, click here

jwt

Using JWT in Node Projects

First of all, let’s create a new project following this link.

Install JWT module with this command:

npm install jsonwebtoken --save

Now open the file config/express.js. Add following line at the top of the file:

var jwt = require('jsonwebtoken');

Now add following middleware just before the glob.sync line. This will be used to verify JWT tokens sent by clients.

We want to verify only POST requests and also, we don’t want to verify token on /login request.

// middleware for token requests
app.use('/', function(req, res, next) {
   if (req.originalUrl.indexOf('/login') > -1) {
     next();
     return;
   }

   // check token on every POST request
   if ('POST' == req.method) {
     var token = req.body.token;

     if (token) {
        var secret_key = 'ABCDE12345edcba';

        jwt.verify(token, secret_key, function(err, decoded) {
           if (err) {
              return res.json({
                STATUS: false,
                message: 'Failed to authenticate token.'
              });
           } else {
              req.decoded = decoded;
              delete req.body.token;
              next();
           }
        });
     } else {
        // if there is no token
        return res.status(403).send({
           STATUS: false,
           message: 'No token provided.'
        });
     }
   } else if ('GET' == req.method || 'OPTIONS' == req.method) {
     next();
   } else {
     // Return Forbidden
     return res.status(403).send({
        STATUS: false,
        message: 'This http method is not allowed.'
     });
   }
});
var controllers = glob.sync(config.root + '/app/controllers/*.js');
...

Now, we will create a controller for login. Create a new file named login.js under app/controllers directory with following code:

var express = require('express'), 
    jwt = require('jsonwebtoken'),
    router = express.Router();

module.exports = function (app) {
   app.use('/', router);
};

router.post('/login', function(req, res) {
   var username = req.body['username'];
   var password = req.body['password'];

   var valid = username == 'dummy' && password == 'correct';
   
   if(valid){
     var json_result;
     var secretKey = 'ABCDE12345edcba';

     // generate token according to username
     var tokenKey = {
        TOKEN_KEY: username
     };
     var token = jwt.sign(tokenKey, secretKey, {
        expiresIn: 900  //15 mins
     });

     json_result = {
        token: token,
        STATUS: true
     };
   } else {
     json_result = {
        STATUS: false
     };
   }
   res.writeHead(200, { 'Connection': 'Close', 'Content-Type': 'application/json', 'Transfer-Encoding': "" }); 
   res.write(JSON.stringify(json_result));
   res.end();
});

router.post('/say-hello', function(req, res) {
   var name = req.body['name'];
   res.write("Hello " + name);
   res.end();
});

Start your web server with following command:

node app.js

Now open POSTMAN and send a POST request with these settings:

POST:   http://localhost:3000/say-hello

You should get token error.

Now execute following URL first while passing username, password in body:

POST:   http://localhost:3000/say-hello
BODY:   x-www-form-urlencoded
username: dummy
password: correct

You will get the JWT token in response. Copy it and pass it in request body along with name in following URL:

POST:   http://localhost:3000/say-hello
BODY:   x-www-form-urlencoded
name: Daya
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJUT0tFTl9LRVkiOiJkdW1teSIsImlhdCI6MTQ4NzMxMTE3MiwiZXhwIjoxNDg3MzEyMDcyfQ.A0zssRiAi0B3ByvFRHxEihTHRKeLbJv0y0S3WrcySkk

Make sure you change the value of token to whatever you got in login. This time you should see the hello message.