Ok. Let's understand JWT Token...

Anmol SinghAnmol Singh
3 min read

What is a JWT Token?

JWT (JSON Web Token) is like a sealed envelope that proves your identity.

Imagine you're at Blow-Up Club in Bonn. At the entrance, the bouncer checks your ID and stamps your hand. That stamp (your JWT) says, "This person has been verified — let them in."

  • The stamp = your token

  • The bouncer = your authentication logic

  • Once stamped, you don’t need to show your ID every time — just the stamp.

A JWT is:

  • Signed using a secret so it can’t be forged.

  • Compact, so it's easy to send in HTTP headers.

  • Stateless — the server doesn’t store sessions. The token carries everything it needs.


What I Had Initially:

My Express backend had this basic login route:

const SECRET_KEY = "supersecretadmin"

app.post("/admin/login", (req, res) => {
  const { secret } = req.body;
  if (secret === SECRET_KEY) {
    res.json({ message: "Access Granted" });
  } else {
    res.json({ message: "Invalid Secret" });
  }
});

It worked for basic checking, but…

  • No token was generated

  • No secure login session

  • No way to protect admin-only routes


Step 1: Add JWT to Backend:

I installed the jsonwebtoken package:

npm install jsonwebtoken

Then I updated my /admin/login route:

const jwt = require("jsonwebtoken")
const JWT_SECRET = "jwtsecrethere"

app.post("/admin/login", (req, res) => {
  const { secret } = req.body;
  if (secret === SECRET_KEY) {
    const token = jwt.sign({ role: "admin" }, JWT_SECRET, { expiresIn: "1h" });
    res.json({ message: "Access Granted", token });
  } else {
    res.status(401).json({ message: "Invalid Secret" });
  }
});

Now the backend returns a token if the secret is valid.


Step 2: Store the Token on Frontend:

In my React frontend, I stored the token in localStorage after login:

localStorage.setItem("adminToken", data.token);

This lets me attach the token to future requests.


Step 3: Add the Token to API Calls:

In my custom useFetch hook or Axios config:

const token = localStorage.getItem("adminToken");
if (token) {
  headers.Authorization = `Bearer ${token}`;
}

This ensures all protected requests carry the JWT token.


Step 4: Protect Backend Routes with Middleware:

To restrict access to certain routes, I added a verifyToken middleware:

const verifyToken = (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (!authHeader?.startsWith("Bearer ")) {
    return res.status(403).json({ message: "No token provided" });
  }

  const token = authHeader.split(" ")[1];

  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ message: "Invalid or expired token" });
  }
};

Usage:

app.get("/admin/data", verifyToken, (req, res) => {
  res.json({ message: "You have admin access" });
});

Final Workflow:

  1. User enters secret and clicks login.

  2. Backend checks secret and returns a JWT.

  3. Frontend stores the token in localStorage.

  4. All future API requests send the token.

  5. Backend protects routes using verifyToken middleware.


What I Learned:

  • Simple secrets aren't secure enough for real apps.

  • JWTs let us manage sessions without storing user data on the server.

  • Protecting routes with middleware is a clean and reusable approach.

0
Subscribe to my newsletter

Read articles from Anmol Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anmol Singh
Anmol Singh

MERN stack developer in progress. Learning by doing, building by sharing. Open to internships, freelance work, or junior roles where I can grow while delivering value.