Handle Access and Refresh Tokens in Your Application

Imagine a digital fortress where access tokens act like keys to a treasure vault. The catch? These keys expire often, forcing guardians to constantly return to the gatekeeper for new ones. Frustration may lead to weaker key choices, posing a security risk. Without a way to selectively replace compromised keys, a security breach can disrupt every user.

Introducing magical refresh tokens allows users to seamlessly get new keys, reducing the risk of weak choices. In case of a breach, selectively replacing compromised keys becomes possible, safeguarding the digital treasures. This combo of access and refresh tokens boosts security, ensuring a robust defense against potential intruders.

So, in this blog, we are going to learn how to use Access Token and Refresh Token with JWT. For this, I am going to use the MERN stack to build the application.

Before moving to access and refresh tokens, let's learn what JWT is.

What is JWT ?

JWT stands for JSON Web Token, which is an open standard used to securely transmit information between parties in the form of a JSON object. A JWT is composed of three parts separated by dots: a header, a payload, and a signature.

Here is an example of JWT:

To understand more, read my blog on JWT Exploitation.

What is Refresh and Access Token ?

Access Token :

  • An access token is like a digital key that grants permission to access specific resources or services within your application.

  • It's a credential with a limited lifespan, acting as proof that the user has the authority to perform certain actions, such as retrieving data or making modifications.

Refresh Token :

  • On the other hand, a refresh token serves as a unique key designed to obtain a new access token when the existing one expires.

  • Unlike access tokens, refresh tokens have a longer lifespan and are securely stored, often in a database. They play a crucial role in refreshing or extending access without necessitating the user to undergo the login process again.

Difference :

  • Access tokens are short-lived and directly utilized for accessing resources.

  • Refresh tokens, with their extended lifespan, are employed to acquire new access tokens without the need for the user to reauthenticate.

Why do we store Refresh Tokens in the database?

First is Enhanced Security, storing refresh tokens in the database adds an extra layer of security by keeping them away from the client-side.

Secondly Safer Compromise Handling, in case of an access token compromise, database-stored refresh tokens enable a more targeted response without disrupting everyone's access.

Create Refresh and Access Token

For this, I am going to use npm libraries like jsonwebtoken to create tokens in JavaScript.

Let's create Access Token :

import jwt from "jsonwebtoken";

const generateToken = (payload,expiry) => {
  return jwt.sign(payload, process.env.JWT_SECRET, {
    expiresIn: expiry,
  });
};

export default generateToken;

Inside the generateToken function, this line uses the jwt.sign method from the jsonwebtoken library to create a new JWT. It takes three arguments:

  • payload: The information you want to include in the token, provided as the first argument.

  • process.env.JWT_SECRET: The second argument is the secret key used to sign the token. It's typically stored in an environment variable for security reasons.

  • { expiresIn: "15m" }: An optional configuration object specifying the expiration time of the token. In this case, the token will expire in 15 minutes.

Similarly, we can create a refresh token, you just need to change the expiresIn value to 7d or any number of days you wish to specify.

Handling Access and Refresh Token

To store and send tokens, we use cookies to securely send and store them in the application. To illustrate this, I am going to use the Express.js (web application framework) to create a server and securely send a cookie to the application.

  1. Install Express.js library.

     npm i express
    
  2. Create a simple server

     import express from "express";
    
     const app = express();
    
     app.use(express.json());
    
     app.get("/", (req, res) => {
       res.status(200).json({ success: "Hello there" });
     });
    
     app.listen(5000, () => {
       console.log("Server started at 5000");
     });
    
  3. Now, to handle cookies, we are going to need a library called cookie-parser. This library parses cookies and places the cookie information on the req object within the middleware.

     import cookieParser from "cookie-parser";
    
     app.use(cookieParser());
    
  4. Now, let's create a simple login API to send the cookie to the frontend.

     import express from "express";
    
     const router = express.Router();
    
     router.post("/api/v1/users/login", asyc (req,res) => {
         try{
           .
           .
           .
           // Find user from database
          let payload = { email: userFound.email, _id: userFound._id };
          let accessToken = generateToken(payload,"15m");
          // Create a refresh token with different private key
          let refreshToken = generateToken(payload,"7d"); 
    
          // set option for cookie
          // this make the cookie only modified by the server
          const option = {
           httpOnly: true,
           secure: true,
          };   
    
          // Now we can use cookie object which was set by cookie-parser
          return res
         .status(200)
         .cookie("accessToken", accessToken, option)
         .cookie("refreshToken", refreshToken, option)
         .json(
           {success: "Logged in successfully"}
         );
         }catch{
           console.error(error);
           res.status(500).json({ error });
         }
     })
    
  5. See how easily we can create an Access Token and Refresh Token and send them to the application. Now, you can test it on Postman to gain a better understanding.

To gain a clearer understanding, you can check out the video by Hitesh Choudhary

Conclusion

In summary, access and refresh tokens play a crucial role in ensuring secure and user-friendly authentication processes for web applications. Access tokens serve as short-term keys, granting users specific access, while refresh tokens extend this access without requiring frequent logins. Developers can easily manage these tokens using tools such as jsonwebtoken and cookies, enhancing both security and user experience. This approach minimizes the risk of compromised tokens.

Reference