QR CookingNotes

CookingNotes

Your Personal Recipe Book

Get it on Google Play
QR FiNoteMe

FiNoteMe

Smart Finance Tracker

Get it on Google Play
programming Learn how to build secure JWT authentication in Node.js and Express with login, access tokens, refresh tokens, and real-world best practices. A practical, step-by-step guide.

How do I implement secure JWT authentication in Node.js + Express step-by-step?

5 Min Read Verified Content

If you're building a modern backend — for a mobile app, SPA frontend, or API — chances are you’ll eventually need JWT authentication.

The common problem developers search for is:

“How do I build login with JWT securely?”

So let’s solve that — cleanly and safely.


🔍 What is JWT (in simple words)?

A JSON Web Token is just a signed string that proves who the user is.

Example token:

xxxxx.yyyyy.zzzzz

It contains:

✔ user data (e.g. user ID)
✔ expiry time
✔ a cryptographic signature

Think of it like a signed ticket.
If the signature is valid → the ticket is trusted.


🔧 Step 1 — Setup Project

mkdir jwt-auth-demo cd jwt-auth-demo npm init -y npm install express jsonwebtoken bcryptjs dotenv

Create a basic server:

const express = require("express"); const app = express(); app.use(express.json()); app.listen(5000, () => console.log("Server running on port 5000"));

🔑 Step 2 — Create Users (Mock for Now)

In real apps you use a database.
Here we fake it to keep things simple:

const users = [];

🔐 Step 3 — Register User (Hash Password)

const bcrypt = require("bcryptjs"); app.post("/register", async (req, res) => { const { email, password } = req.body; const hashed = await bcrypt.hash(password, 10); users.push({ email, password: hashed }); res.json({ message: "User registered" }); });

Now passwords are not stored in plain text (good).


🔑 Step 4 — Generate JWT on Login

const jwt = require("jsonwebtoken"); require("dotenv").config(); app.post("/login", async (req, res) => { const { email, password } = req.body; const user = users.find(u => u.email === email); if (!user) return res.status(400).json({ message: "User not found" }); const match = await bcrypt.compare(password, user.password); if (!match) return res.status(400).json({ message: "Wrong password" }); const token = jwt.sign( { email: user.email }, process.env.JWT_SECRET, { expiresIn: "15m" } ); res.json({ token }); });

Create .env:

JWT_SECRET=supersecretlongstring

🛡 Step 5 — Protect Routes with Middleware

function auth(req, res, next) { const header = req.headers["authorization"]; const token = header && header.split(" ")[1]; if (!token) return res.sendStatus(401); jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.sendStatus(403); req.user = user; next(); }); }

Use it:

app.get("/profile", auth, (req, res) => { res.json({ email: req.user.email }); });

Now:

✔ valid token → access granted
❌ no token → denied
❌ expired token → denied

Exactly how secure APIs should behave.


🔁 Bonus — Refresh Tokens (Avoid Frequent Login)

Access tokens should expire fast.

So we add a refresh token:

app.post("/refresh", (req, res) => { const { token } = req.body; jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.sendStatus(403); const newToken = jwt.sign( { email: user.email }, process.env.JWT_SECRET, { expiresIn: "15m" } ); res.json({ token: newToken }); }); });

Now users stay logged in without extending access token expiry dangerously.


🧠 Common Mistakes (And Fixes)

❌ Storing JWT in LocalStorage

👉 Vulnerable to XSS.

Use HTTP-only cookies when possible.


❌ Tokens That Never Expire

👉 Huge security risk.

Always set expiry.


❌ Using Weak Secrets like “12345”

👉 Use a long random secret.


📌 Quick Checklist for Production

✔ HTTPS only
✔ HttpOnly cookie if possible
✔ Short-lived access token
✔ Refresh token rotation
✔ Logout invalidates refresh token
✔ Use a real DB


🏁 Final Thoughts

JWT authentication seems scary at first — but when broken down step-by-step, it’s very logical:

👉 verify user → sign token → protect routes → expire safely

Now you have a clean foundation you can actually use in real projects.

Advertisement
Back to Programming