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 serviceswithin 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.
Install Express.js library.
npm i express
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"); });
Now, to handle cookies, we are going to need a library called
cookie-parser
. This library parsescookies
and places the cookie information on thereq
object within themiddleware
.import cookieParser from "cookie-parser"; app.use(cookieParser());
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 }); } })
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.