Understanding JWT Authentication in Node.js

Imagine you build a website where users can:
log in
upload files
create posts
view private data
Now think about this question:
How does the server know which user is making the request?
If someone opens:
/profile
how can the server decide:
whether the user is logged in
whether access should be allowed
This is where authentication comes in.
In this article, you'll learn:
what authentication means
what JWT is
JWT structure
how login works with tokens
sending tokens with requests
protecting routes using JWT
Everything will stay beginner-friendly and practical.
What Authentication Means
Authentication simply means:
Verifying who a user is
Example from real life:
When you enter a building, security may ask for:
ID card
fingerprint
password
After verification, you are allowed inside.
Web applications work similarly.
Why Authentication is Required
Without authentication:
anyone could access private data
users could modify other accounts
admin pages would be exposed
Example:
/dashboard
should only be accessible to logged-in users.
Authentication helps the server identify users safely.
Traditional Authentication vs Token Authentication
Earlier websites often used:
sessions
cookies stored on server
Modern applications commonly use:
- JWT tokens
Why?
Because JWT authentication is:
simple
scalable
stateless
What Does “Stateless” Mean?
Stateless means:
Server does not store login information manually for every user
Instead:
the client stores the token
the token is sent with every request
The server only verifies the token.
Simple Real-World Analogy
Think of a movie ticket.
After buying a ticket:
you receive proof
staff checks the ticket later
they don't repeatedly ask for payment proof
JWT works similarly.
After login:
server gives a token
client stores it
token is shown with future requests
What is JWT?
JSON Web Token stands for:
JSON Web Token
It is a compact string used for:
authentication
user verification
protected routes
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
It may look scary initially…
But conceptually, it’s just a digital identity card.
JWT Authentication Flow
Installing JWT Package
Most Node.js apps use:
jsonwebtoken
Install it:
npm install jsonwebtoken
Creating a Simple JWT
const jwt = require("jsonwebtoken");
const token = jwt.sign(
{ id: 1, name: "Aman" },
"secretkey"
);
console.log(token);
This creates a JWT token.
Understanding jwt.sign()
jwt.sign(payload, secret)
Payload
Contains user data.
Example:
{
id: 1,
name: "Aman"
}
Secret
Used to verify token authenticity.
"secretkey"
In real apps:
store secrets in environment variables
never hardcode them
Structure of a JWT
A JWT has 3 parts:
HEADER.PAYLOAD.SIGNATURE
Example:
xxxxx.yyyyy.zzzzz
Each section has a purpose.
1. Header
Contains metadata about the token.
Example:
{
alg: "HS256",
typ: "JWT"
}
This tells:
token type
algorithm used
2. Payload
Contains actual user data.
Example:
{
id: 1,
role: "user"
}
Common payload data:
user ID
email
role
Important:
Do NOT store sensitive data like:
passwords
credit card info
inside JWT payloads.
3. Signature
Used to verify:
token integrity
token authenticity
The server checks:
whether token was modified
whether token is valid
You usually don't handle this manually.
Libraries handle it automatically.
Login Flow Using JWT
Let’s create a very basic login example.
Login Route
app.post("/login", (req, res) => {
const user = {
id: 1,
email: "aman@gmail.com"
};
const token = jwt.sign(user, "secretkey");
res.json({
token
});
});
When login succeeds:
token gets generated
token is sent to client
What Happens After Login?
The frontend stores the token.
Usually inside:
localStorage
cookies
Example:
localStorage.setItem("token", token);
Now the user is considered logged in.
Sending Token with Requests
When accessing protected routes, the client sends the token.
Usually inside request headers.
Example:
fetch("/profile", {
headers: {
Authorization: token
}
});
The server reads this token and verifies it.
Protecting Routes Using Tokens
Suppose this route should only work for logged-in users:
/profile
We create middleware to verify JWT.
JWT Verification Middleware
function verifyToken(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.send("Access denied");
}
jwt.verify(token, "secretkey", (err, decoded) => {
if (err) {
return res.send("Invalid token");
}
req.user = decoded;
next();
});
}
Using Protected Routes
app.get("/profile", verifyToken, (req, res) => {
res.json({
message: "Protected data",
user: req.user
});
});
Now:
- only valid tokens can access this route
Before vs After Authentication
Without Authentication
Anyone can access:
/profile
No restrictions.
With JWT Authentication
Only users with valid tokens can access protected routes.
Complete Minimal Example
const express = require("express");
const jwt = require("jsonwebtoken");
const app = express();
app.use(express.json());
function verifyToken(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.send("Access denied");
}
jwt.verify(token, "secretkey", (err, decoded) => {
if (err) {
return res.send("Invalid token");
}
req.user = decoded;
next();
});
}
app.post("/login", (req, res) => {
const user = {
id: 1,
name: "Aman"
};
const token = jwt.sign(user, "secretkey");
res.json({ token });
});
app.get("/profile", verifyToken, (req, res) => {
res.json({
message: "Protected route",
user: req.user
});
});
app.listen(3000, () => {
console.log("Server running");
});
Important Beginner Security Tips
Never Store Passwords Inside JWT
Wrong:
{
password: "123456"
}
JWT payloads are readable after decoding.
Use Strong Secret Keys
Weak secrets are dangerous.
Bad:
"123"
Better:
process.env.JWT_SECRET
Add Token Expiry
Tokens should expire after some time.
Example:
jwt.sign(user, "secretkey", {
expiresIn: "1h"
});
This improves security.
Simple Real-World Analogy
Imagine entering a concert.
After verification:
- you receive a wristband
Security later checks:
- wristband validity
instead of asking for your identity repeatedly.
JWT tokens work similarly.
Small Practice Assignment
Task 1
Create a login route that returns a JWT token.
Task 2
Send the token using request headers.
Task 3
Create middleware that:
checks token existence
verifies token
Task 4
Protect a route like:
/dashboard
using JWT middleware.
Task 5
Add token expiry using:
expiresIn
