How to Implement JSON Web Token (JWT) Authentication in Node.js
Introduction
In this guide, we dive into JSON Web Token (JWT) authentication in Node.js to ensure secure access to your API. We’ll cover everything from setting up JWT to validating it on protected routes. By the end of this tutorial, you’ll be able to implement robust authentication for your Node.js applications.
Setting Up JWT in Node.js
We start by installing the necessary dependencies. Run the following command to install the jsonwebtoken
library along with its TypeScript types:
npm install jsonwebtoken npm install --save-dev @types/jsonwebtoken
Configuring the Secret Key
To sign and verify JWTs, we need a secret key. Open your .env
file and add:
APP_SECRET=your-32-character-secret-key
Then, in config.ts
, load this secret:
export const config = { appSecret: process.env.APP_SECRET || "default_secret", };
Issuing a Test JWT
We will simulate an authentication server that issues JWTs. Create issue-test-token.ts
in the src
directory:
import jwt from "jsonwebtoken"; import { config } from "./config"; const payload = { sub: "" }; // Replace with a real user ID const token = jwt.sign(payload, config.appSecret, { expiresIn: "1h", issuer: "task-manager-app", }); console.log("Generated Token:", token);
Run the script using:
npx ts-node -r dotenv/config src/issue-test-token.ts
Copy the generated token and decode it at jwt.io to understand its structure.
🚀Boost your career with 👉 IBM Full Stack Software Developer Certificate
Implementing JWT Authentication Middleware
To authenticate API requests, create authenticate-user.ts
in the middleware
folder:
import { Request, Response, NextFunction } from "express"; import jwt, { JwtPayload } from "jsonwebtoken"; import { config } from "../config"; export const authenticateUser = (req: Request, res: Response, next: NextFunction) => { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith("Bearer ")) { return res.status(401).json({ message: "Authorization header missing or malformed" }); } const token = authHeader.split(" ")[1]; try { const payload = jwt.verify(token, config.appSecret) as JwtPayload; req.auth = { payload, token }; next(); } catch (error) { res.status(403).json({ message: "You are not authorized to perform this operation" }); } };
Extending Express Request Type
To add auth
property to Express request, create express.d.ts
in src
:
declare global { namespace Express { interface Request { auth?: { payload: JwtPayload; token: string; }; } } }
Protecting API Routes
Import and apply the authentication middleware in the route files:
import { authenticateUser } from "../../middleware/authenticate-user"; router.get("/tasks", authenticateUser, getTasks); router.get("/projects", authenticateUser, getProjects);
Restricting Access to User Data
Modify the controllers to ensure users can only access their own data:
const tasks = await prisma.task.findMany({ where: { user_id: req.auth?.payload.sub }, });
Similarly, update project controllers:
const projects = await prisma.project.findMany({ where: { user_id: req.auth?.payload.sub }, });
Testing the Authentication Flow
Using API testing tools like Postman or VS Code’s api-test.http
file, send a request without the authorization header. You should get a 401 Unauthorized
error.
Now, add the token as a Bearer
token in the header and resend the request. You should receive the authenticated user’s data.
Conclusion
That’s a wrap on JWT authentication in Node.js! Now you know how to secure API endpoints, validate user access, and protect sensitive data using JSON Web Tokens. Instead of building your own authentication server, consider integrating services like Auth0 for enhanced security. Check out our next guide on using Auth0 for authentication!