Skip to main content
Node.js Basics
CHAPTER 24 Beginner

JWT Authentication

Updated: May 13, 2026
35 min read

# JWT Authentication

Welcome to Chapter 24! In the last chapter, we successfully verified a user's password. But there is a massive problem: HTTP is a stateless protocol.

This means the server has amnesia. It treats every single request as completely independent. If a user logs in, the server says "Success!". But 1 second later, if the user requests their private /dashboard, the server says "Who are you?".

To solve this, we give the user a digital ID card after they log in. Every time they make a new request, they show this ID card to the server. The modern standard for this ID card is a JSON Web Token (JWT).

---

1. Introduction

A JSON Web Token (JWT) is a long, scrambled string of characters generated by your server.

The Workflow:

  1. 1. Login: User sends email/password. Server verifies with bcrypt.
  1. 2. Issue Token: Server uses the jsonwebtoken package to generate a token containing the user's database id. It sends this token back to the client.
  1. 3. Store Token: The frontend (React/Browser) saves this token (usually in LocalStorage).
  1. 4. Access Protected Route: The client wants to view /api/dashboard. They send a GET request and attach the JWT in the request headers.
  1. 5. Verify Token: The server intercepts the request using a custom Middleware, verifies the token is valid, and lets them in.

---

2. Learning Objectives

By the end of this chapter, you will be able to:

  • Install the jsonwebtoken package.
  • Understand the structure of a JWT (Header, Payload, Signature).
  • Sign (create) a token when a user successfully logs in.
  • Create an authMiddleware to protect private routes.
  • Extract and verify a token from incoming request headers.

---

3. Beginner-Friendly Explanations

The Secret Key

To generate a JWT, your server needs a Secret Key (just a long, random string of text like "mySuperSecretKey123"). When the server issues a token, it uses this secret key to "sign" it. When the client sends the token back, the server uses the *same* secret key to verify it. If a hacker tries to forge a fake token, the server will reject it because the hacker doesn't know your secret key.

The Payload

The token holds data inside it (the Payload). Usually, we put the user's database
id inside the token. That way, when the server verifies the token, it immediately knows exactly *which* user is making the request.

---

4. Syntax Explanation

Let's see how to generate a token inside our Login route.

```javascript id="ch24-syntax-1" // 1. Require the package const jwt = require('jsonwebtoken');

// (Inside your login route, AFTER bcrypt.compare is successful)

// 2. Define the payload (the data you want to embed in the token) const payload = { userId: user._id };

// 3. Define your secret key const SECRET = "mySuperSecretPassword123";

// 4. Sign the token // Arg 1: Payload, Arg 2: Secret, Arg 3: Expiration time const token = jwt.sign(payload, SECRET, { expiresIn: '1h' });

// 5. Send the token back to the user res.status(200).json({ message: "Login successful", token: token });

1234567891011121314151617181920
**Output Explanation:**
The client receives a response containing a token that looks something like: `eyJhbGciOiJIUzI1Ni...`. This token will automatically expire and become invalid after 1 hour.

---

## 5. Real-world Examples

**Theme Parks:**
A JWT is exactly like a wristband at a theme park.
- **Login:** You pay at the front gate (provide email/password).
- **Issue Token:** The cashier puts a wristband on you (JWT).
- **Protected Routes:** You walk up to a roller coaster. The attendant (Middleware) looks at your wristband. If it's real and hasn't expired, you get to ride. You don't have to pay (log in) again for every single ride!

---

## 6. Multiple Code Examples

### Example 1: The Protected Route
Let's create a route that only logged-in users can access.

javascript id="ch24-code-1" // We apply our custom 'verifyToken' middleware (which we write next) app.get('/api/dashboard', verifyToken, (req, res) => { // If the middleware allows them through, they see this: res.json({ message: "Welcome to your private dashboard!" }); });

1234
### Example 2: The Auth Middleware
This is the bouncer! It intercepts the request and checks the token.
Tokens are traditionally sent in the HTTP Headers under `Authorization: Bearer <token>`.

javascript id="ch24-code-2" const jwt = require('jsonwebtoken'); const SECRET = "mySuperSecretPassword123";

const verifyToken = (req, res, next) => { // 1. Look for the token in the request headers const authHeader = req.header('Authorization'); // 2. If there is no header, reject them if (!authHeader) { return res.status(401).json({ error: "Access Denied. No token provided." }); }

// 3. The header looks like "Bearer eyJhbG...". We split it to just get the token. const token = authHeader.split(' ')[1];

try { // 4. Verify the token using our secret key const decodedPayload = jwt.verify(token, SECRET); // 5. Attach the decoded payload (the userId) to the request object! req.user = decodedPayload; // 6. Let them into the route! next(); } catch (err) { // If token is fake, altered, or expired, it jumps here res.status(403).json({ error: "Invalid or expired token." }); } };

123456789101112131415161718192021222324252627282930313233343536373839404142
---

## 7. Output Explanations

Look at Step 5 in the middleware: `req.user = decodedPayload;`.
Because middleware executes *before* the route, we can attach the user's ID to the `req` object. Now, inside `app.get('/api/dashboard')`, we can write `const userId = req.user.userId;` and use that ID to fetch their specific private data from MongoDB!

---

## 8. Common Mistakes

1. **Putting passwords in the payload:** The payload of a JWT is *Base64 Encoded*, not encrypted! Anyone can decode a JWT payload online. Never put passwords, credit cards, or sensitive secrets in the payload. Only use non-sensitive identifiers like the database `_id`.
2. **Hardcoding secrets:** Writing `const SECRET = "secret123"` in your code is extremely dangerous if you upload to GitHub. In Chapter 27, we will learn how to hide this in an `.env` file.
3. **Forgetting `Bearer `:** When testing with Postman, clients must send the token exactly formatted as `Bearer <token>`. If they just send `<token>`, the `.split(' ')[1]` logic in your middleware will break.

---

## 9. Best Practices

- **Expiration Times:** Always give your tokens an expiration time (`{ expiresIn: '1h' }`). If a hacker steals a token that lasts forever, they have permanent access.
- **Statelessness:** Avoid storing active tokens in your MongoDB database. The beauty of JWT is that the server mathematically verifies the token signature without having to do a slow database query.

---

## 10. Exercises

1. Go to [jwt.io](https://jwt.io). This is the official JWT debugger.
2. Look at the Encoded section on the left. Notice the three colors (Header, Payload, Signature) separated by dots.
3. Look at the Decoded section. Change the "name" in the payload and watch the encoded string change instantly!

---

## 11. Mini Project: Secure API authentication

**Objective:** Combine Chapter 23 and 24 to build a secure API where a user logs in, receives a token, and uses it to access a protected route.

**Step 1:** Installation
`npm install express jsonwebtoken`

**Step 2:** The Code (`jwtApp.js`)
*(We will skip MongoDB here to keep the code short and focus solely on JWT logic).*

javascript id="ch24-mini-project" const express = require('express'); const jwt = require('jsonwebtoken');

const app = express(); app.use(express.json());

const SECRET = "superSecret123";

// Mock Database User const dbUser = { id: 99, email: "user@test.com", password: "password123" };

// --- 1. LOGIN ROUTE --- app.post('/login', (req, res) => { const { email, password } = req.body;

// Simulate checking credentials if (email === dbUser.email && password === dbUser.password) { // Credentials match! Generate Token const token = jwt.sign({ userId: dbUser.id }, SECRET, { expiresIn: '15m' }); return res.json({ message: "Login Success", token: token }); } res.status(401).json({ error: "Invalid credentials" }); });

// --- 2. AUTH MIDDLEWARE --- const verifyToken = (req, res, next) => { const authHeader = req.header('Authorization'); if (!authHeader) return res.status(401).json({ error: "No token" });

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

try { const decoded = jwt.verify(token, SECRET); req.user = decoded; // Attach { userId: 99 } to req next(); } catch (err) { res.status(403).json({ error: "Invalid token" }); } };

// --- 3. PROTECTED ROUTE --- // Must pass through verifyToken middleware first app.get('/profile', verifyToken, (req, res) => { // We have access to req.user because the middleware attached it! res.json({ message: "Welcome to your profile!", yourId: req.user.userId }); });

app.listen(3000, () => console.log("JWT Server Running")); ``

---

12. Coding Challenges

Challenge 1: Create a second protected route /settings. Apply the verifyToken middleware to it. Verify that a user cannot access it without a token.

Challenge 2: Modify the jwt.sign configuration to make the token expire in 5s (5 seconds). Log in, grab the token, wait 6 seconds, and try to access /profile. Observe the "Invalid token" error because it expired!

---

13. MCQs with Answers

Q1: What does JWT stand for? A) JavaScript Web Transfer B) JSON Web Token C) Java Web Transaction D) JSON Window Tracker Answer: B

Q2: What is the main purpose of a JWT in web development? A) To securely hash passwords in the database. B) To act as a digital ID card to keep users authenticated across stateless HTTP requests. C) To encrypt the database connection. D) To format HTML templates. Answer: B

Q3: Is the Payload of a JWT encrypted and hidden from the public? A) Yes, it is fully encrypted. B) No, it is merely Base64 encoded and can be decoded by anyone. Answer: B

Q4: Where does the client typically place the JWT when sending a request to a protected API route? A) In the req.body B) In the URL parameters C) In the Authorization HTTP header D) In a hidden HTML input Answer: C

---

14. Interview Questions

  1. 1. How does the server know a JWT is authentic and wasn't forged by a hacker?
*Answer:* The third part of a JWT is the Signature. The server generates this signature by running the Header and Payload through an algorithm along with a private
SECRET key known only to the server. When a token is sent back, the server re-runs the algorithm. If the signatures don't match, the server knows the payload was tampered with or forged.
  1. 2. Why is it dangerous to put a password in a JWT payload?
*Answer:* The payload is just Base64 encoded, not encrypted. Anyone who intercepts the token (or steals it from the browser) can easily decode the payload and read the password in plain text.

---

15. FAQs

Q: Do I need to use cookies instead? A: You can! JWTs can be stored in LocalStorage (accessed via JS) or in HttpOnly Cookies (handled automatically by the browser). Storing JWTs in HttpOnly cookies is technically more secure against Cross-Site Scripting (XSS) attacks, but sending them via headers (as shown here) is standard practice for mobile app APIs and React Single Page Applications.

Q: How do I "logout" a user if I'm using JWT? A: Because JWTs are stateless, the server doesn't "remember" the token. To log a user out, you simply delete the token from the frontend (e.g., localStorage.removeItem('token')). If they don't have the token, they can't access protected routes anymore!

---

16. Summary

  • HTTP is stateless. We use JWTs to maintain user sessions.
  • Use jwt.sign() during login to generate a token containing the user's _id.
  • The client sends the token back in the Authorization: Bearer <token> header.
  • Custom Middleware intercepts the request and uses jwt.verify() to check the token.
  • If valid, the middleware attaches the payload to req.user and calls next().

---

17. Next Chapter Recommendation

We can authenticate users and handle text data seamlessly. But what if a user wants to upload a profile picture? express.json` cannot handle image files! In Chapter 25: File Uploads with Multer, we will learn how to intercept incoming files, validate them, and save them to our server's hard drive!

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·