Understanding JWT Tokens using Node.js.

So, We will be checking how to use jwt token for api authorization. For the sake of this tutorial I won’t be using any database for data but rather an npm module called faker. This faker package will give us fake data that we would use to generate token . The generated token will be used by a different route to give the user encoded user information.

So, let’s just get started by creating a node package and installing the required dependencies. We will be using the json web token npm package.

npm init -y & npm i express jsonwebtoken faker

Create Basic API Routes

var express = require('express');
var jwt = require('jsonwebtoken');
var faker = require('faker');

const app = express();
const PORT = 4000;

app.get('/api/user/getAuthToken', (req, res)=>{
    res.status(200).json({token:"We will get token"})
})

app.get('/api/user/getUserData', (req, res)=>{
    res.status(200).json({user:"USER DATA HERE"})
});

app.listen(PORT, _=> console.log(`SERVER STARTED RUNNING on ${PORT}`));

This is a fairly simple express app. I hope you understand the code snippet(i.e., if you understand expressjs) because if you don’t you are not yet ready to learn about JWT using Node.js. We mentioned before We Won’t be using any database but rather an NPM package called Faker to generate fake data. Now what this will do is that we would be having two routes first would generate for us a token by creating a fake user and send us the JWT token. The second route would accept this JWT token and return us the decoded user object.

Create a Fake User Generator function

var generateFakeUser =()=>{
    return {
        name: faker.name.findName(),
        email:faker.internet.email(),
        phoneNumber: faker.phone.phoneNumber()
    }
}

All this function does is use faker to generate a fake user object with fake name, email, and phoneNumber. Now that we are done setting up our project we will start working with JWT.

Generating Auth Token.

var generateAuthToken = function (user) {
    const token = jwt.sign(user, "{SECRET_KEY}", { expiresIn:  3600 });
    return token;
}

We can create a JWT token using the sign method in jsonwebtoken package.

What is a JSON Web Token ?

Very simply put, JSON Web Token is an internet standard for creating data with encryption whose payload holds JSON. The tokens are signed using a key.

Structure of a JWT token

//jwt token
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7Im5hbWUiOiJFbGVub3JhIFN0b2tlcyIsImVtYWlsIjoiVG95MjlAeWFob28uY29tIiwicGhvbmVOdW1iZXIiOiIoNDY5KSA4MzEtNjkzMiB4ODgwIn0sImlhdCI6MTU5MDE0ODAwOCwiZXhwIjoxNTkwMjM0NDA4fQ.dkJ_fIGi_lU3o9j1tv52IfakX6yMA27Bh_sPwAEs-mU"

The gibberish that you see above is a JSON Web Token example. As you can see a Json web token is seperated into three parts by dots (“.”) .

These three parts are:

  • Header
  • Payload
  • Signature

The header basically gives information on type of algorithm used to encode the data and a type which is JWT.

The second is the payload it is the data that is encoded.

The third is the signature json web tokens uses private key to encode data the signature is used to verify whether or not data was altered before it reached its destination.

Understanding JWT sign method

jwt sign method takes in a couple of arguments two of which are required while other are optional . The first argument is the payload data i.e., the data you want to encode. In our case it is the user object .Now, the payload is a string that can represent a valid JSON. If it is not a string the sign method will use JSON.stringify method to convert the object to string.

If you don’t pass a valid json you will end up receiving an error. The second required argiment is a Private Key that would be use for encoding of the payload . You will use this Private key to decode the JWT token you created in the verify method.

Let’s discuss some optional argument. here we see we passed an optional parameter named expiresIn. This expires In takes either a numerical value represented in seconds or you can pass a sting but then you need to provide the time unit ex days hours etc. For eg:

For 2 days you can set exipresIn to “2d” for 2 hours the value would be “2h”. If you don’t provide a unit say you just set expiresIn to “2” that would be interpreted as 2ms.

By default the encryption algorithm used is HMAC SHA256 but you can use other algorithms like RSA SHA256 by providing it as algorithm in the same object as expiresIn. for ex:

jwt.sign(data, "{SECRET_KEY}",{ algorithm:'HS256', expiresIn:"1d"});

You can also generate a jwt in Backdate by providing another argument named iat (Issued at time). Which will overwrite the current timestamp that you receive by default.

jwt.sign({data,iat : Math.floor(Date.now() / 1000) - 60 *60}, "{SECRET_KEY}",  {algorithm:'HS256', expiresIn:"1d"});

The above code generates a token with 1 hour of backdate.

So Our route “/api/user/getAuthToken” will use the above code to generate JWT token

var generateAuthToken = function (data) {
   return  jwt.sign({data,iat : Math.floor(Date.now() / 1000) - 60 *60}, "{SECRET_KEY}",  {algorithm:'HS256', expiresIn:"1d"});    
}

app.get('/api/user/getAuthToken', (req, res)=>{
    var user = generateFakeUser();
    var token = generateAuthToken(user)
    console.log(user)
    res.status(200).json({token})
})

Understanding JWT verify method

Now, We have created the JWT token using the sign method. We need a mechanism to decode and check whether this token is actually valid for this purpose we have a method called verify. So, We can say that JSON web token authentication is checked at this point.

var decoded = jwt.verify(token,"{SECRET_KEY}");

The verify method takes in two required parameters and a couple of optional parameters. The first parameter that it takes is the JWT token we wish to verify. The second required argument is the value of the Private key we used to sign the token.

If the token is not valid it will throw an error and if it valid it will return the original payload. So we wrap it in a try catch block

var auth = (req,res) => {
    try {
        const token = req.headers.authorization;
        const decoded = jwt.verify(token,"{SECRET_KEY}");
        res.send(decoded);
    } catch (error){
        return res.status(401).json({message:"Authetication failed"});
    }
}

app.get('/api/user/getUserData', auth)

Here we are using the auth function declared above to send a response when we hit the route “/api/user/getUserData” but ideally you should rather use it as middleware on the API’s where you wish to had this authentication layer implemented. for example:

var auth = (req,res, next) => {
    try {
        const token = req.headers.authorization;
        const decoded = jwt.verify(token,"{SECRET_KEY}");
        req.user = decoded;
        next();
    } catch (error){
        return res.status(401).json({message:"Authetication failed"});
    }
}

app.get('/api/user/getUserData', auth,(req, res)=>{
    //do something
    res.send(200).json({user:req.user})
})

Now We attach the user object to the req object when we are able to verify the jwt else we send and authentication failure response from the middleware.

Entire Code

var express = require('express');
var jwt = require('jsonwebtoken');
var faker = require('faker');

const app = express();
const PORT = 4000;

var generateFakeUser =()=>{
    return {
        name: faker.name.findName(),
        email:faker.internet.email(),
        phoneNumber: faker.phone.phoneNumber()
    }
}
var generateAuthToken = function (data) {
    const token = jwt.sign({data,iat : Math.floor(Date.now() / 1000) - 60 *60}, "{SECRET_KEY}",  {algorithm:'HS256', expiresIn:"1d"});
    return token;
}

var auth = (req,res) => {
    try {
        const token = req.headers.authorization;
        const decoded = jwt.verify(token,"{SECRET_KEY}");
        res.send(decoded);
    } catch (error){
        return res.status(401).json({message:"Authetication failed"});
    }
}
app.get('/api/user/getAuthToken', (req, res)=>{
    var user = generateFakeUser();
    var token = generateAuthToken(user)
    console.log(user)
    res.status(200).json({token})
})

app.get('/api/user/getUserData', auth)

app.listen(PORT, _=> console.log(`SERVER STARTED RUNNING on ${PORT}`))

Leave a Reply