This blog is a beginner-friendly introduction to JWT (JSON Web Tokens). It explains the basics of what JWTs are, how they work, and why they are used for secure authentication in modern applications. You’ll learn about the structure of a JWT , library for JWT and common use cases such as user login and API authentication.
What is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe token used to securely transmit information between parties. It’s commonly used for authentication and information exchange in web applications.
Structure
A JSON Web Token is nothing but a long encoded text string which is made up of three parts separated by a period. These parts are:
Header
Payload
Signature
A typical JWT looks like the following:
header.payload.signature
A JWT is composed of three parts:
Header: Contains metadata about the token, such as the algorithm used for signing.
Payload: Contains claims — pieces of information (like user ID or roles).
Signature: Verifies the token’s integrity and authenticity.
Example of a JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywicm9sZSI6ImFkbWluIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Why Use JWT?
Here are some reasons developers love JWT:
Stateless Authentication:This means that the server does not need to store any session data, which makes the system more scalable.
Compact: Being lightweight makes JWTs easy to pass in URLs, headers, or cookies.
Secure: Signed tokens ensure data integrity and, optionally, confidentiality.
Cross-domain authentication: JWT is great for applications where the client and server are in different domains.
How Does JWT Work?
User Login:
- A user logs in with credentials (e.g., username and password).
Token Generation:
- The server validates the credentials and generates a JWT containing user-specific data (e.g., user ID).
Token Storage:
The client stores the JWT (commonly in localStorage or cookies).
cookies are more secure because they can be HttpOnly, but localStorage is easier to access from JavaScript.
Token Usage:
For subsequent requests, the client includes the JWT in the Authorization header:
Authorization: Bearer <your-token>
Token Verification:
- The server verifies the token’s signature to ensure it’s valid and unaltered.
Installation
To start working with JSON Web Tokens (JWT) in your Node.js application, you need to install the jsonwebtoken
library. This library provides the necessary functions to generate, verify, and decode JWTs.
npm install jsonwebtoken // for npm
yarn add jsonwebtoken // for yarn
After installing jsonwebtoken import the jwt from ‘jsonwebtoken’ in your file.
import jwt from 'jsonwebtoken';
Additional Setup:
You also need to make sure you have a secret key (JWT_SECRET
) to sign and verify the JWTs. This key should be kept secure and not exposed in your codebase. You can store it in an environment variable (process.env.JWT_SECRET
), for example:
Create a
.env
file in the root of your project.Add your secret key to the
.env
file:JWT_SECRET=your-secret-key
Use a package like
dotenv
to load the.env
file into your Node.js application:npm install dotenv // for npm yarn add dotenv // for yarn
Import
dotenv
and load the environment variables at the start of your application:import dotenv from 'dotenv'; dotenv.config(); // Loads the .env file into process.env
Now you're ready to start using JWT in your project. You can generate tokens with jwt.sign()
, verify them with jwt.verify()
, and decode them with jwt.decode()
.
There are three main funtion used from jwt.
jwt.sign ( Payload, JWT_SECRET, Expire Time ): It is used to generate the JWT Token, where
Payload: The data you want to include in the JWT. It can be any valid JSON data you want to encode in the token.
JWT_SECRET: A secret key used to sign the JWT and verify its authenticity. It should be kept secure and only known to the parties involved in the token exchange.
Expire Time: The duration after which the JWT will expire and no longer be valid.
example :
const JWT_SECRET = process.env.JWT_SECRET;
const accessToken = jwt.sign({ email: UserExist.email }, JWT_SECRET, {
expiresIn: '5m',
});
We create the JWT with the user’s email as the payload, using the secret key to sign it, and set it to expire in 5 minutes.
jwt.verify ( Token, JWT_SECRET, (err, decoded) => { } ): It is used to verify and decode the JWT Token, where
Token: The JWT token you want to verify. It is a string containing the payload and signature of the JWT.
JWT_SECRET: A secret key used to sign the JWT and verify its authenticity. It should be kept secure and only known to the parties involved in the token exchange.
(err, decoded) => { }: A callback function called when the verification process is complete. It takes two arguments:
err
anddecoded
.
example:
jwt.verify(refreshToken, JWT_SECRET, (err, decoded) => {
if (err) {
return res
.status(StatusCodes.FORBIDDEN)
.json({ message: 'Invalid refresh token' });
}
jwt.decode(Token): It is used to decode a JWT Token, where
- Token: The JWT token you want to decode. It is a string containing the payload and signature of the JWT. Unlike
jwt.verify()
,jwt.decode()
does not verify the signature but simply extracts the payload from the token.
- Token: The JWT token you want to decode. It is a string containing the payload and signature of the JWT. Unlike
const decoded = jwt.decode(token);
Error Handling in JWT Verification
When verifying a JWT, it's important to handle errors gracefully. Common errors include invalid tokens, expired tokens, or malformed tokens. You can handle these errors using try/catch
blocks or by handling specific error types in the callback function passed to jwt.verify
.
Example using try/catch
with jwt.verify
:
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET;
const verifyToken = (req, res, next) => {
// Get token from Authorization header
const token = req.headers['authorization']?.split(' ')[1];
if (!token) {
return res.status(403).json({ message: 'No token provided' });
}
try {
// Verify the token
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded; // Attach decoded user info to the request object
next(); // Move to the next middleware or route handler
} catch (err) {
if (err.name === 'JsonWebTokenError') {
return res.status(400).json({ message: 'Invalid token' });
}
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ message: 'Token has expired' });
}
return res.status(500).json({ message: 'Internal server error' });
}
};
Explanation:
Error Handling: In this example, we first check if the
Authorization
header exists and extract the token. If no token is provided, we send a403
response indicating that the request is forbidden due to the lack of a token.try/catch
Block: Thetry/catch
block is used to handle potential errors during JWT verification.If the token is invalid,
jwt.verify
will throw aJsonWebTokenError
, and we respond with a400
status code.If the token has expired, a
TokenExpiredError
will be thrown, and we respond with a401
status code, indicating that the token is no longer valid.If an unexpected error occurs, we send a generic
500
server error message.
Set Token in Cookies
const accessToken = jwt.sign({ email: UserExist.email }, JWT_SECRET, {
expiresIn: '5m',
});
res.cookie('saroj-x-access-token', accessToken, {
maxAge: 1000 * 60 * 5, // expire after 15 minutes
httpOnly: true, // Cookie will not be exposed to client side code
secure: true, // use with HTTPS only
sameSite: 'none', //
});
Tips for Secure JWT Implementation
Use HTTPS: Always transmit JWTs over secure connections.
Set Expiry Times: Define short expiration times to limit token misuse.
Validate Signatures: Ensure tokens are signed with a strong, secret key.
Avoid Sensitive Data: Never store sensitive information (like passwords) in the payload.
Implement Token Blacklisting: Use blacklists for compromised tokens.
Conclusion
JWTs are a powerful tool for modern authentication systems, offering a stateless and secure way to manage user sessions and API access. By understanding the basics and following best practices, you can confidently implement JWTs in your projects.
Ready to try it out? Start with your favorite framework or library and integrate JWT into your authentication workflow!