{"id":4359,"date":"2021-03-27T15:46:10","date_gmt":"2021-03-27T10:16:10","guid":{"rendered":"https:\/\/codeforgeek.com\/?p=4359"},"modified":"2023-12-22T19:04:39","modified_gmt":"2023-12-22T13:34:39","slug":"refresh-token-jwt-nodejs-authentication","status":"publish","type":"post","link":"https:\/\/codeforgeek.com\/refresh-token-jwt-nodejs-authentication\/","title":{"rendered":"Nodejs Authentication Using JWT and Refresh Token"},"content":{"rendered":"<p>Nodejs authentication using JWT a.k.a JSON web token is very useful when you are developing a cross-device authentication mechanism. <\/p>\n<p>Here is how token-based authentication works:<\/p>\n<ul>\n<li>User logins to the system and upon successful authentication, the user are assigned a token which is unique and bounded by time limit say 15 minutes<\/li>\n<li>On every subsequent API call, the user provides the access token in order to consume the system resources.<\/li>\n<li>When time is expired, the user has to login again to get a new token<\/li>\n<\/ul>\n<p>The last step is frustrating, we can&#8217;t ask users to log in each and every single time once the token is expired.<\/p>\n<p>There are two ways to solve this:<\/p>\n<ol>\n<li>Increase the time of the token<\/li>\n<li>Use refresh token to extend the token<\/li>\n<\/ol>\n<p>I have covered token-based authentication in <a href=\"https:\/\/codeforgeek.com\/token-based-authentication-using-nodejs-rethinkdb\/\" rel=\"noopener noreferrer\" target=\"_blank\">this article<\/a> in detail.<\/p>\n<p>In this Nodejs authentication tutorial, I am going to build a simple\/boilerplate solution to handle the refresh token mechanism in Nodejs authentication.<\/p>\n<blockquote><p>Full disclosure: Code is not production grade, it is meant for the explanation purpose only.<\/p><\/blockquote>\n<p>So let&#8217;s begin.<\/p>\n<h2>Creating the Project<\/h2>\n<p>Let&#8217;s get straight to the code.<\/p>\n<p>You need to create a new folder and run the following command to initialize the new Nodejs project.<\/p>\n<p><code>npm init --y<\/code><\/p>\n<p>This will create a new package.json file.<\/p>\n<\/h3>\n<p>Installing dependencis<\/h3>\n<p>You need few dependencies to run the project. Install them using the following command.<br \/>\n<code>npm i --S express body-parser jsonwebtoken<\/code><\/p>\n<p>Once they are installed, you are good to go.<\/p>\n<h3>Adding Gitignore<\/h3>\n<p>You need to add this file to avoid certain folders being added to the Git repository.<\/p>\n<p>To do this, you need to create a new file and name it <strong>.gitignore<\/strong> and add the following line.<\/p>\n<p><code><br \/>\nnode_modules\/<br \/>\n<\/code><\/p>\n<p>This means, avoid adding node modules folder in the git repository.<\/p>\n<p>Ok, let&#8217;s write some code.<\/p>\n<h2>Creating Server and adding routes<\/h2>\n<p>I am going to use express to create a Nodejs server. Here is the code.<\/p>\n<div class='file_name'>app.js<\/div>\n<p><code lang='javascript'><br \/>\nconst express = require('express')<br \/>\nconst bodyParser = require('body-parser')<br \/>\nconst jwt = require('jsonwebtoken')<br \/>\nconst router = express.Router()<br \/>\nconst config = require('.\/config')<br \/>\nconst tokenList = {}<br \/>\nconst app = express()<\/p>\n<p>router.get('\/', (req,res) => {<br \/>\n    res.send('Ok');<br \/>\n})<\/p>\n<p>router.post('\/login', (req,res) => {<br \/>\n    const postData = req.body;<br \/>\n    const user = {<br \/>\n        \"email\": postData.email,<br \/>\n        \"name\": postData.name<br \/>\n    }<br \/>\n    \/\/ do the database authentication here, with user name and password combination.<br \/>\n    const token = jwt.sign(user, config.secret, { expiresIn: config.tokenLife})<br \/>\n    const refreshToken = jwt.sign(user, config.refreshTokenSecret, { expiresIn: config.refreshTokenLife})<br \/>\n    const response = {<br \/>\n        \"status\": \"Logged in\",<br \/>\n        \"token\": token,<br \/>\n        \"refreshToken\": refreshToken,<br \/>\n    }<br \/>\n    tokenList[refreshToken] = response<br \/>\n    res.status(200).json(response);<br \/>\n})<\/p>\n<p>router.post('\/token', (req,res) => {<br \/>\n    \/\/ refresh the damn token<br \/>\n    const postData = req.body<br \/>\n    \/\/ if refresh token exists<br \/>\n    if((postData.refreshToken) && (postData.refreshToken in tokenList)) {<br \/>\n        const user = {<br \/>\n            \"email\": postData.email,<br \/>\n            \"name\": postData.name<br \/>\n        }<br \/>\n        const token = jwt.sign(user, config.secret, { expiresIn: config.tokenLife})<br \/>\n        const response = {<br \/>\n            \"token\": token,<br \/>\n        }<br \/>\n        \/\/ update the token in the list<br \/>\n        tokenList[postData.refreshToken].token = token<br \/>\n        res.status(200).json(response);<br \/>\n    } else {<br \/>\n        res.status(404).send('Invalid request')<br \/>\n    }<br \/>\n})<\/p>\n<p>router.use(require('.\/tokenChecker'))<\/p>\n<p>router.get('\/secure', (req,res) => {<br \/>\n    \/\/ all secured routes goes here<br \/>\n    res.send('I am secured...')<br \/>\n})<\/p>\n<p>app.use(bodyParser.json())<br \/>\napp.use('\/api', router)<br \/>\napp.listen(config.port || process.env.port || 3000);<br \/>\n<\/code><\/p>\n<p>Here is the config file.<\/p>\n<div class='file_name'>config.json<\/div>\n<p><code lang='javascript'><br \/>\n{<br \/>\n    \"secret\": \"some-secret-shit-goes-here\",<br \/>\n    \"refreshTokenSecret\": \"some-secret-refresh-token-shit\",<br \/>\n    \"port\": 3000,<br \/>\n    \"tokenLife\": 900,<br \/>\n    \"refreshTokenLife\": 86400<br \/>\n}<br \/>\n<\/code><\/p>\n<p>In the login route, we are doing the token generation. <\/p>\n<p>Notice these two lines:<br \/>\n<code lang='javascript'><br \/>\n    const token = jwt.sign(user, config.secret, { expiresIn: config.tokenLife})<br \/>\n    const refreshToken = jwt.sign(user, config.refreshTokenSecret, { expiresIn: config.refreshTokenLife})<br \/>\n<\/code><\/p>\n<p>I am using different secrets and times to expire for both of the keys and storing the keys in an array using the following code.<br \/>\n<code lang='javascript'><br \/>\n    tokenList[refreshToken] = response<br \/>\n<\/code><\/p>\n<blockquote><p>Tip: You must use the store instead of an array in production, such as Redis.<\/p><\/blockquote>\n<p>In the token route, I am expecting the refresh token in the payload, if the payload exists, I am checking if it is a valid token. <\/p>\n<p>If it is a valid token, I am creating a new token and sending it back to the user. This way user doesn&#8217;t need to log in again.<\/p>\n<h2>Creating middleware to authenticate the API calls<\/h2>\n<p>You need to have a piece of code that always executes and check if the token coming in the API calls is valid or not.<\/p>\n<p>If you have noticed, I have added this middleware code in the Server code.<\/p>\n<p><code lang='javascript'><br \/>\nrouter.use(require('.\/tokenChecker'))<br \/>\n<\/code><\/p>\n<p>Here is the code for this middleware.<\/p>\n<div class='file_name'>tokenChecker.js<\/div>\n<p><code lang='javascript'><br \/>\nconst jwt = require('jsonwebtoken')<br \/>\nconst config = require('.\/config')<\/p>\n<p>module.exports = (req,res,next) => {<br \/>\n  const token = req.body.token || req.query.token || req.headers['x-access-token']<br \/>\n  \/\/ decode token<br \/>\n  if (token) {<br \/>\n    \/\/ verifies secret and checks exp<br \/>\n    jwt.verify(token, config.secret, function(err, decoded) {<br \/>\n        if (err) {<br \/>\n            return res.status(401).json({\"error\": true, \"message\": 'Unauthorized access.' });<br \/>\n        }<br \/>\n      req.decoded = decoded;<br \/>\n      next();<br \/>\n    });<br \/>\n  } else {<br \/>\n    \/\/ if there is no token<br \/>\n    \/\/ return an error<br \/>\n    return res.status(403).send({<br \/>\n        \"error\": true,<br \/>\n        \"message\": 'No token provided.'<br \/>\n    });<br \/>\n  }<br \/>\n}<br \/>\n<\/code><\/p>\n<p>It&#8217;s simple token validation. This way all the API calls which are below this middleware have to provide a valid token to consume the system&#8217;s resources.<\/p>\n<h2>Testing the code<\/h2>\n<p>Let&#8217;s do some testing.<\/p>\n<p>Run the code using the following command.<\/p>\n<p><code>node app.js<\/code><\/p>\n<p>Open your favorite API testing tool, mine is Postman, and hit the \/login API route.<\/p>\n<p><code><br \/>\nURL: http:\/\/localhost:3000\/api\/login<br \/>\nbody: {<br \/>\n\t\"email\": \"shahid@codeforgeek.com\",<br \/>\n\t\"name\": \"Shahid\"<br \/>\n }<br \/>\n<\/code><\/p>\n<p>Here is the sample screenshot to refer to.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Login-api-calls.png\" alt=\"Login api call - Nodejs authentication\" width=\"1124\" height=\"604\" class=\"aligncenter size-full wp-image-4451\" srcset=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Login-api-calls.png 1124w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Login-api-calls-300x161.png 300w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Login-api-calls-768x413.png 768w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Login-api-calls-1024x550.png 1024w\" sizes=\"(max-width: 1124px) 100vw, 1124px\" \/><\/p>\n<p>Now copy the token and use it to access the \/secure API route.<\/p>\n<p>Refer to this screenshot for help.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/access-resource-using-token.png\" alt=\"access resource using token\" width=\"1124\" height=\"424\" class=\"aligncenter size-full wp-image-4452\" srcset=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/access-resource-using-token.png 1124w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/access-resource-using-token-300x113.png 300w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/access-resource-using-token-768x290.png 768w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/access-resource-using-token-1024x386.png 1024w\" sizes=\"(max-width: 1124px) 100vw, 1124px\" \/><\/p>\n<p>Now, let&#8217;s do a token exchange, shall we?<\/p>\n<p>You need to call \/token route and provide the refresh token to obtain a new token. Refer to the screenshot below for the payload example.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Token-exchange.png\" alt=\"Token exchange\" width=\"1122\" height=\"541\" class=\"aligncenter size-full wp-image-4453\" srcset=\"https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Token-exchange.png 1122w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Token-exchange-300x145.png 300w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Token-exchange-768x370.png 768w, https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/Token-exchange-1024x494.png 1024w\" sizes=\"(max-width: 1122px) 100vw, 1122px\" \/><\/p>\n<h2>Download the code<\/h2>\n<p>The source code is open source and you can clone, distribute and download it from the Github. Click <a href=\"https:\/\/github.com\/codeforgeek\/node-refresh-token\/\" rel=\"noopener noreferrer\" target=\"_blank\">here<\/a> to view the repository.<\/p>\n<h2>Conclusion<\/h2>\n<p>Nodejs authentication using tokens is an integral part of web development. You need to use the refresh token mechanism for the seamless flow of the application. We covered the basics of it and I am sure you can take it from there. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nodejs authentication using JWT a.k.a JSON web token is very useful when you are developing a cross-device authentication mechanism. Here is how token-based authentication works: User logins to the system and upon successful authentication, the user are assigned a token which is unique and bounded by time limit say 15 minutes On every subsequent API [&hellip;]<\/p>\n","protected":false},"author":69,"featured_media":4467,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_surecart_dashboard_logo_width":"180px","_surecart_dashboard_show_logo":true,"_surecart_dashboard_navigation_orders":true,"_surecart_dashboard_navigation_invoices":true,"_surecart_dashboard_navigation_subscriptions":true,"_surecart_dashboard_navigation_downloads":true,"_surecart_dashboard_navigation_billing":true,"_surecart_dashboard_navigation_account":true,"_uag_custom_page_level_css":"","footnotes":""},"categories":[14,22],"tags":[],"class_list":["post-4359","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-nodejs","category-express"],"blocksy_meta":[],"uagb_featured_image_src":{"full":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920.jpg",1920,1280,false],"thumbnail":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920-150x150.jpg",150,150,true],"medium":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920-300x200.jpg",300,200,true],"medium_large":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920-768x512.jpg",768,512,true],"large":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920-1024x683.jpg",1024,683,true],"1536x1536":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920.jpg",1536,1024,false],"2048x2048":["https:\/\/codeforgeek.com\/wp-content\/uploads\/2018\/03\/computer-767784_1920.jpg",1920,1280,false]},"uagb_author_info":{"display_name":"Pankaj Kumar","author_link":"https:\/\/codeforgeek.com\/author\/pankaj\/"},"uagb_comment_info":0,"uagb_excerpt":"Nodejs authentication using JWT a.k.a JSON web token is very useful when you are developing a cross-device authentication mechanism. Here is how token-based authentication works: User logins to the system and upon successful authentication, the user are assigned a token which is unique and bounded by time limit say 15 minutes On every subsequent API&hellip;","_links":{"self":[{"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/posts\/4359","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/users\/69"}],"replies":[{"embeddable":true,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/comments?post=4359"}],"version-history":[{"count":0,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/posts\/4359\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/media\/4467"}],"wp:attachment":[{"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/media?parent=4359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/categories?post=4359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codeforgeek.com\/wp-json\/wp\/v2\/tags?post=4359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}