JWT Node.js Authentication

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!

Share this article

Similar Posts