JSON Web Token (JWT) in node.js (Implementing using Refresh token)
In this tutorial, we will see how we can implement JWT in a node js application with access tokens as well as refresh tokens. This tutorial expects that you already have a working project, the code blocks are for reference purposes and to help you understand the logic.
The node module which we will be using is jsonwebtoken
Read about JWT (what, why, when) on jwt.io
Understanding token format: A JWT token has 3 parts separated by a “ . ”. The first part is the header which specifies information like the algorithm used to generate the signature (Third part). The second is the payload which is the information we are trying to save and the third is the signature. The First 2 parts are not encrypted. They are just base64 encoded which you can easily view by decoding on an online tool.
Implementation using middleware in Express.js
npm install jsonwebtoken
MiddleWare code for an access token
const jwt = require("jsonwebtoken");
AuthenticateJWT(req, res, next){
const authHeader = req.headers['authorization']
if (authHeader == null) return
next({status:401,message:'authorization missing'})
jwt.verify(authHeader, Constant.ACCESS_TOKEN_SECRET,(err, user) =>
{
if (err) return next({status:403,message:err.message})
req.user = user;
next()
})
},
ACCESS_TOKEN_SECRET
is a secret key you use to generate JWT, In the example we are saving it in constant but for security, you should use an environment variable to pass this key. below code will generate a 32 bytes secret or you can use any random secret code.
Generating secret key
require('crypto').randomBytes(32, function(err, buffer) {
var ACCESS_TOKEN_SECRET = buffer.toString('hex');
});
The API request would look like
app.get('/api/userOrders', AuthenticateJWT, (req, res) => {
// executes after authenticateToken
// ...
})
The above code was how you will authenticate the JWT, now we will see how to generate the JWT for access and refresh. use the below function to generate JWT after authenticating your user from your database. it will create 2 tokens one is an access token (expires in 5 minutes) and the other is a refresh token (expires in 6 hours).
Generating access tokens
//payload can be userID, email or other user detailsfunction generateAccessToken(payload, ip_address) {return new Promise(function (resolve, reject) {var tokens = {};//generating acess token
tokens.accessToken = jwt.sign(payload, Constant.ACCESS_TOKEN_SECRET, { expiresIn: '5m' });//generating refresh token
tokens.refreshToken = jwt.sign(payload, Constant.ACCESS_TOKEN_SECRET, { expiresIn: '6h' });resolve(tokens);})};
We keep a short expiry time for an access token (JWT) that has user data to make it more secure but we do not expect users to sign in every 5 minutes. So we use refresh token for this. Every time your access token expires the application can use a refresh token to verify the user and issue a new access token.
Client-Side Token Handling
When the client receives the token, they often want to store it for gathering user information in future requests. The most popular manner for storing auth tokens are cookies and localStorage.
Why Refresh token?
Refresh tokens help in getting new access tokens without asking users to sign in again. It is handled by the application itself. you provide your Client-Side app with two different tokens, one is an access token and the other is a refresh token.
JSON web token has a drawback:
you can’t Revoke access of a user till he has access and refresh token with him. So to tackle this we save the refresh token in a temporary location like a variable (map, array, etc) or Redis. every time users need a new token, match your refresh token with one in your Redis and authenticate the token with JWT as we have done for the access token. now for the revoking access you can just delete that token from your Redis.
Saving refresh token
var refreshTokens={};
//here userID is saved in payload of refresh token
refreshTokens[userId] = refreshToken;
Authenticate refresh token and issue new tokens
//decode the JWT Token
var decoded = jwt.decode(JWTRefreshToken);
//check in temp location
if(refreshTokens[decoded.userid] === JWTRefreshToken)
// verify refresh token using jwt "AuthenticateJWT" function mentioned above and generate new access and refresh token for further use.
Here Client-Side application can check if the access token is expired and using refresh token can ask for new access and refresh token. without letting the user know about this. This way users can sign in once and use the application seamlessly. This also allows an administrator to block certain users by deleting their refresh token
var decoded = jwt.decode(JWTRefreshToken);
delete refreshTokens[decoded.userid];