DEV Community

suraj kushwaha
suraj kushwaha

Posted on

Authentication in Express with Mongoose (Step-by-Step Guide)

Authentication is one of the most important parts of any web application. Without it, your users can’t securely log in, access their data, or trust your app. In this guide, we’ll learn how to implement authentication in Express.js using Mongoose with JWT (JSON Web Tokens).

By the end, you’ll have a working setup with Register, Login, and Protected Routes.

Step 1: Setup the Project

Initialize a new project:
mkdir express-auth && cd express-auth
npm init -y

Install dependencies:
npm install express mongoose bcrypt jsonwebtoken dotenv cors
npm install --save-dev nodemon

Project structure:
📂 express-auth
┣ 📂 models
┃ ┗ user.model.js
┣ 📂 routes
┃ ┗ auth.routes.js
┣ 📂 middlewares
┃ ┗ auth.middleware.js
┣ server.js
┣ .env

Step 2: Connect to MongoDB

Inside server.js

import express from "express";
import mongoose from "mongoose";
import dotenv from "dotenv";
import cors from "cors";

dotenv.config();

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

mongoose
  .connect(process.env.MONGO_URI)
  .then(() => console.log("MongoDB connected"))
  .catch((err) => console.error(err));

app.listen(5000, () => console.log("Server running on port 5000"));

Enter fullscreen mode Exit fullscreen mode

Step 3: Create User Model

models/user.model.js

import mongoose from "mongoose";
import bcrypt from "bcrypt";

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

// Hash password before saving
userSchema.pre("save", async function (next) {
  if (!this.isModified("password")) return next();
  this.password = await bcrypt.hash(this.password, 10);
  next();
});

const User = mongoose.model("User", userSchema);
export default User;

Enter fullscreen mode Exit fullscreen mode

Auth Routes (Register & Login)

*routes/auth.routes.js
*

import express from "express";
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";
import User from "../models/user.model.js";

const router = express.Router();

// Register
router.post("/register", async (req, res) => {
  try {
    const { name, email, password } = req.body;
    const existing = await User.findOne({ email });
    if (existing) return res.status(400).json({ message: "User already exists" });

    const user = new User({ name, email, password });
    await user.save();

    res.status(201).json({ message: "User registered successfully" });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

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

    const user = await User.findOne({ email });
    if (!user) return res.status(400).json({ message: "Invalid credentials" });

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

    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });

    res.json({ token, user: { id: user._id, name: user.name, email: user.email } });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

export default router;

Enter fullscreen mode Exit fullscreen mode

🛠️ Step 5: Middleware for Protecting Routes

middlewares/auth.middleware.js

import jwt from "jsonwebtoken";

export const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(" ")[1]; // Bearer <token>
  if (!token) return res.status(401).json({ message: "No token provided" });

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch {
    res.status(401).json({ message: "Invalid token" });
  }
};

Enter fullscreen mode Exit fullscreen mode

✅ Best Practices

🔒 Never store plain-text passwords. Always hash them.

⏳ Use short-lived JWTs + refresh tokens for long sessions.

🔑 Keep your JWT_SECRET safe and outside source code.

🍪 Prefer HttpOnly cookies for storing tokens in production.

🌐 Always use HTTPS in production.

🎯 Conclusion

You just built authentication in Express with Mongoose and JWT!
We created a User model, added Register/Login routes, generated JWT tokens, and protected routes with a middleware.

👉 Next steps:

Add role-based authorization (admin, user, etc.)

Implement refresh tokens for longer sessions

Add OAuth (Google/GitHub login)

🔥 That’s it! You now have a secure authentication system in your Express app.

Top comments (0)