Implement JWT with Node.js
As we know, JWT(JSON Web Token) is very useful in the authorization scenario. Here, I will list all steps when I need to get JWT in Node.js.
I Initial preparations
If you haven’t already, set up the Node environment for this project. Then, install the following packages that we will be using for this tutorial.
- Express: The Node.js framework we will be using
- Cookie-Parser: Since we will be sending the JWT token in a cookie, use this package to parse the cookie sent along with requests
- Body-Parser: This package to parses the body of incoming requests to extract POST parameters
Dotenv: This package loads environment variables from .env file to the application environment - Json-Web-Token: This is the package that helps us with the JWT implementation
You can install these packages using the following command.
npm install express cookie-parser body-parser dotenv json-web-token --save
In the next steps, we will implement the functions inside controller.js, which we have used in the above code. We use the login function to handle post requests sent to the /login route and log in users. We use refresh function to handle post requests sent to the /refresh route and issue new access tokens using the refresh token.
II Set up environment variables
Before implementing the logic to log a user in, we need to set up the environment variables that are needed to configure JWTs. Create a .env file and add these two variables that we will be using inside the application.
1 | ACCESS_TOKEN_SECRET=swsh23hjddnns |
You can add any string as the secret. It’s recommended to use a longer secret with random characters as a security measure. The expiration time of an access token we create will be 120 seconds. We also set the secret to signing the refresh token and its expiration time. Note how the refresh token has a longer lifetime compared to the access token.
III Handle user login and JWT token creation
Now we can get to the step of implementing the login function we imported to the app.js file to handle the /login route.
We are going to store an array of user objects in the application for the purpose of this implementation. In a real-world scenario, you will be retrieving this user information from a database or any other location. When implementing the login function, first we need to retrieve the username and password sent with the login POST request.
If the request doesn’t contain either the username or the password, the server responds with a 401 unauthorized status. The same response applies if the password sent with the request does not match the password stored in the database for that particular username.
If the client has sent correct credentials to the server, then we proceed to log in the user to the system by issuing new JWT tokens. In this case, the new logging-in user receives two tokens: access token and refresh token. The access token is then sent along with the response inside a cookie back to the client. The refresh token is stored in the database for issuing access tokens in the future. In our case, we will store the refresh token in the user array we previously created.
1 | const jwt = require('json-web-token') |
When sending the access token inside a cookie, remember to set the httpOnly flag to prevent attackers from accessing the cookie from the client-side. We have also set the secure flag in the above example. However, if you are only trying out this code over an HTTP connection, not an HTTPS connection, remove the secure flag to send it with the response.
IV Add a middleware to authenticate user requests
The server needs to check whether a user has logged in before giving access to certain routes. We can use the access token sent in a cookie with every request to verify that the user is, in fact, authenticated. This process is carried out in a middleware.
Let’s create a new file named middleware.js and implement the verify method to check whether the user is authenticated.
First, we should retrieve the access token from the cookie sent with the request. If the request does not contain the access token, it will not proceed to the intended route and instead, return a 403 forbidden error.
1 | const jwt = require('json-web-token') |
If the request contains the access token, then the server will verify whether it was issued by the server itself using the stored secret. In case the token is expired or recognized as a one not signed by the server, the jsonwebtoken’s verify method will throw an error. We can handle the error to return a 401 error back to the client.
1 | const jwt = require('json-web-token') |
Now we can use this middleware to protect any route that requires the users to be logged in before accessing. Import the middleware to the place you are handling routes, which, in our case, is app.js. If we are trying to protect a route named /comments, it can be easily achieved by adding the middleware before the route handler.
1 | const {verify} = require('./middleware') |
The request will be passed on to the route handler only if the user is authenticated.
V Issuing new access token using the refresh token
Now we can implement this refresh function to issue new access tokens using the stored refresh token.
The function used here, refresh, is also inside the controller.js file we used before for the login function implementation.
The first part of this function is much like what we did to verify an access token: Check whether the access token was sent and verify the token.
1 | exports.refresh = function (req, res){ |
Then, we are going to retrieve the refresh token of this particular user using the username stored in access token’s payload. Once the refresh token is verified, the server will issue a new access token as implemented in the login function.
If the refresh token is expired or fails to verify, the server will return an unauthorized error. Otherwise, the new access token will be sent in the cookie.
1 | exports.refresh = function (req, res){ |
VI Summary
In this artical, I wrote the steps of implementing authentication with JWT in Node.js. As a continuation of our previous post, where we discussed the theories behind JWT authentication, our implementation was focused on adhering to the best practices we discussed before. As a result, our JWT implementation made use of cookies to send JWTs and refresh tokens to generate new access tokens. If you are willing to take a step ahead of this implementation, you can come up with a solution to re-issue refresh tokens within a short timespan to avoid security breaches.





