DEV Community

Cover image for Implementing Authentication Using JWT and Passport.js: A Beginner’s Guide
Hardik Gayner
Hardik Gayner

Posted on

Implementing Authentication Using JWT and Passport.js: A Beginner’s Guide

Introduction

Authentication is a crucial part of web applications, ensuring that only authorized users can access certain resources. One of the most secure and scalable authentication methods is JWT (JSON Web Token) authentication. In this guide, we will implement JWT authentication using Passport.js, a popular authentication middleware for Node.js.

What is JWT?

JSON Web Token (JWT) is a compact, URL-safe token format used for securely transmitting information between parties as a JSON object. It consists of three parts:

  1. Header – Contains metadata about the token (e.g., algorithm used).
  2. Payload – Contains user-related data (e.g., user ID).
  3. Signature – Ensures the token's integrity and authenticity.

Why Use Passport.js?

Passport.js is a middleware that simplifies authentication in Node.js applications. It supports various strategies, including JWT authentication.

Project Setup

Step 1: Initialize a Node.js Project

mkdir jwt-auth-example
cd jwt-auth-example
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Required Dependencies

npm install express passport passport-jwt jsonwebtoken dotenv bcryptjs mongoose
Enter fullscreen mode Exit fullscreen mode
  • express – Web framework for Node.js
  • passport – Authentication middleware
  • passport-jwt – JWT strategy for Passport.js
  • jsonwebtoken – Library for generating JWTs
  • dotenv – Loads environment variables
  • bcryptjs – Hashes passwords securely
  • mongoose – MongoDB ORM

Building the Authentication System

Step 3: Create the Folder Structure

jwt-auth-example
│── config/
│   ├── passport.js
│── models/
│   ├── User.js
│── routes/
│   ├── auth.js
│── server.js
│── .env
│── package.json
Enter fullscreen mode Exit fullscreen mode

Step 4: Setup MongoDB and User Model

Connect to MongoDB

Create a .env file and add your MongoDB connection string:

MONGO_URI=mongodb://localhost:27017/jwt-auth
JWT_SECRET=your_secret_key
Enter fullscreen mode Exit fullscreen mode

Create User.js Model (inside models/ folder)

const mongoose = require("mongoose");

const UserSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

module.exports = mongoose.model("User", UserSchema);
Enter fullscreen mode Exit fullscreen mode

Step 5: Configure Passport.js for JWT Authentication

Create passport.js (inside config/ folder)

const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const User = require("../models/User");
const dotenv = require("dotenv");

dotenv.config();

const opts = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: process.env.JWT_SECRET,
};

module.exports = (passport) => {
  passport.use(
    new JwtStrategy(opts, async (jwt_payload, done) => {
      try {
        const user = await User.findById(jwt_payload.id);
        if (user) {
          return done(null, user);
        }
        return done(null, false);
      } catch (err) {
        console.error(err);
      }
    })
  );
};
Enter fullscreen mode Exit fullscreen mode

Step 6: Create Authentication Routes

Create auth.js (inside routes/ folder)

const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const passport = require("passport");
const User = require("../models/User");
const dotenv = require("dotenv");

dotenv.config();
const router = express.Router();

// Register Route
router.post("/register", async (req, res) => {
  const { username, email, password } = req.body;

  try {
    let user = await User.findOne({ email });
    if (user) return res.status(400).json({ msg: "User already exists" });

    const hashedPassword = await bcrypt.hash(password, 10);

    user = new User({ username, email, password: hashedPassword });
    await user.save();
    res.json({ msg: "User registered successfully" });
  } catch (err) {
    res.status(500).json({ msg: "Server error" });
  }
});

// Login Route
router.post("/login", async (req, res) => {
  const { email, password } = req.body;

  try {
    const user = await User.findOne({ email });
    if (!user) return res.status(400).json({ msg: "User not found" });

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return res.status(400).json({ msg: "Invalid credentials" });

    const payload = { id: user.id, username: user.username };

    jwt.sign(
      payload,
      process.env.JWT_SECRET,
      { expiresIn: "1h" },
      (err, token) => {
        if (err) throw err;
        res.json({ token });
      }
    );
  } catch (err) {
    res.status(500).json({ msg: "Server error" });
  }
});

// Protected Route
router.get(
  "/profile",
  passport.authenticate("jwt", { session: false }),
  (req, res) => {
    res.json({ user: req.user });
  }
);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Step 7: Set Up the Server

Create server.js

const express = require("express");
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const passport = require("passport");
const authRoutes = require("./routes/auth");

dotenv.config();
const app = express();

app.use(express.json());

mongoose
  .connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log("MongoDB connected"))
  .catch((err) => console.error(err));

require("./config/passport")(passport);
app.use(passport.initialize());

app.use("/api/auth", authRoutes);

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Testing the Authentication System

  1. Start the Server
   node server.js
Enter fullscreen mode Exit fullscreen mode
  1. Register a User
   curl -X POST http://localhost:5000/api/auth/register -H "Content-Type: application/json" -d '{"username": "hardik", "email": "hardik@example.com", "password": "123456"}'
Enter fullscreen mode Exit fullscreen mode
  1. Login to Get a Token
   curl -X POST http://localhost:5000/api/auth/login -H "Content-Type: application/json" -d '{"email": "hardik@example.com", "password": "123456"}'
Enter fullscreen mode Exit fullscreen mode
  • Copy the received JWT token.
    1. Access the Protected Route
   curl -X GET http://localhost:5000/api/auth/profile -H "Authorization: Bearer YOUR_JWT_TOKEN"
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this guide, we implemented JWT authentication using Passport.js in a Node.js application. We covered:

✅ User registration & password hashing

✅ User login with JWT generation

✅ Protecting routes using Passport.js

This approach ensures secure authentication in modern web applications. 🚀

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more