The Startup
Published in

The Startup

Authentication and Authorization Using JWTs in Node.js

The objective of this article is to implement the concept of access token and refresh token mentioned in the OAuth2.0 specification (RFC 6749). We’ll use JSON Web Tokens (JWT) for this purpose.

For more details about JWTs, please visit the following article.

This project is also available in my GitHub repository.

Project outline

In this project, we’ll create two server applications viz. authentication cum authorization server and resource server. The functions of both the servers are described below.

(i) Authentication cum authorization server — This server will register new users and will enable them to log-in. On successful log-in, it will provide the users with access and refresh tokens, with the help of which the users will be able to access the resource. It will also generate new access tokens once it receives correct refresh token from the user. If the access token gets compromised/stolen from the user, then it will also have the ability to delete the refresh token from the database once the user requests for it. And it will not generate any more access tokens for the user.

(ii) Resource server — This server will verify the access token received from the user and on successful verification, it will allow the user to access the resource.

The users will be able to access all the endpoints using cURL from the terminal.

Now, it’s the time to start building our project.

Initial setup

First of all, we’ll create a directory with the name jwtProject and following diagram shows the files and folders present inside this directory.

We’ll open the terminal and navigate into this directory and run the command npm init and enter all the default option expect for “main” field, where we’ll enter authServer.js (this will be our entry point to our application).

Then we’ll install dependencies like — bcrypt, dotenv, express and jsonwebtoken using the following command.

npm install bcrypt dotenv express jsonwebtoken --save

Bcrypt is a library that helps us to hash passwords.

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. With the help of express, APIs can be build very easily and quickly.

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.

Jsonwebtoken library is an implementation of RFC 7519 that provides various methods to generate JWTs, verify JWTs etc.

After installing these modules, node_modules folder will be created.

The we’ll create the .env file, where we’ll store our secrets for access token and refresh token. This file will have the following content.

ACCESS_TOKEN_SECRET=accesssecret
REFRESH_TOKEN_SECRET=refreshsecret

Developing the backend

I have written some of the codes by taking help from Web Dev Simplified. Please refer to this video if you wish to. I would like to thank Web Dev Simplified for helping me to bring the JWT concept into practice.

Now we’ll create a file with name data.js, which will be used to store the user data upon successful registration.

Then, we’ll write the code for our authentication cum authorization server. For that we’ll create another file with name authServer.js.

This server will listen to the API calls on port 3000. The explanation of all the endpoints defined in the above code is also mentioned along with those endpoints.

Now, we’ll write codes for the resource server in the file resourceServer.js.

This server will listen to the API calls on port 4000.

Testing the application

Now, our application is ready to be tested. We’ll open three terminal windows. In one window, we’ll start our authentication cum Authorization server using the command node authServer.js.

In the second window, we’ll start the resource server using the command node resourceServer.js.

And the third window will be for accessing the APIs. So, in this terminal window, we’ll do the following steps —

  1. User will register itself using the following command.
curl -X POST -H'content-type: application/json' 
-d'{"username":"maverick","email":"mav@gmail.com","password":"mav"}' http://localhost:3000/register

On successful registration, following out will be displayed.

{"message":"Registration successful"}

2. Then, user will log in using the following command.

curl -X POST -H'content-type: application/json' 
-d'{"email":"mav@gmail.com","password":"mav"}' http://localhost:3000/login

On successful log in, the user will get the access token and the refresh token as the output, which is displayed below.

{"AccessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTMsImV4cCI6MTYwNTYyODY3M30._caeM5tWEx30yjoeZNolHaxzVTk-OGrIO1ZZJaZ6Vsw",
"RefreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTN9.AgYPbnNB95wVmhuEqQsr37s1WAnxxy-qGDsbbLrRxCg",
"message":"You are logged-in"}

3. Then, user will include this access token in the request header and will access the resource API running on port 4000.

curl -X GET -H'content-type: application/json' 
-H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTMsImV4cCI6MTYwNTYyODY3M30._caeM5tWEx30yjoeZNolHaxzVTk-OGrIO1ZZJaZ6Vsw' http://localhost:4000/greet

This will give the following output.

{"message":"Whola...you are authorized to access this API"}

4. Then, the user will wait for 2 minutes after which the access token will expire. So, the user has to include the refresh token in the request header and has to contact the authorization server running on port 3000 to get new access token.

curl -X POST -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTN9.AgYPbnNB95wVmhuEqQsr37s1WAnxxy-qGDsbbLrRxCg' -H'content-type: application/json' http://localhost:3000/token

The above command will send new access token to the user.

{"AccessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg4MjYsImV4cCI6MTYwNTYyODg0Nn0.qGRMaVoQJaGPBH2TKebKGNukLwuw0g0zZd89iNv6-NQ",
"message":"This is your new access token"}

With this new access token, the user can again access the resource.

5. Now, suppose the access and refresh token is stolen from the user. So, with this access token, the malicious user can access the resource for only 2 minutes after which it will expire. Then, he can use the refresh token to obtain new access token. So, that’s how, the malicious user will have complete access to the resource. To mitigate this problem, user will call the /delRefreshToken endpoint with the refresh token included in the header of the request, which will delete the refresh token and the malicious user won’t be able to obtain any new access tokens.

curl -X DELETE -H'content-type: application/json' 
-H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTN9.AgYPbnNB95wVmhuEqQsr37s1WAnxxy-qGDsbbLrRxCg' http://localhost:3000/delRefreshToken

The above command will give the following output.

{ "message":"Refresh token deleted successfully" }

6. Now, when the malicious user will try to obtain a new access token from the authorization server with the stolen refresh token using the following command.

curl -X POST -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hdkBnbWFpbC5jb20iLCJpYXQiOjE2MDU2Mjg2NTN9.AgYPbnNB95wVmhuEqQsr37s1WAnxxy-qGDsbbLrRxCg' -H'content-type: application/json' http://localhost:3000/token

It will give the following output.

{"message":"Forbidden"}

So, we have created our application successfully which is performing the desired function.

References

https://youtu.be/mbsmsi7l3r4

Video on JWT authentication tutorial.

https://tools.ietf.org/html/rfc7519

RFC 7519- JSON Web Token (JWT)

https://tools.ietf.org/html/rfc6749

RFC 6749- OAuth 2.0 Authorization Framework

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store