DEV Community

Cover image for Implementing "Forgot Password" with MongoDB: A Step-by-Step Guide
pwnkdm
pwnkdm

Posted on

Implementing "Forgot Password" with MongoDB: A Step-by-Step Guide

A "Forgot Password" feature is essential for any user authentication system. It enhances user experience and security by allowing users to reset their passwords safely. In this guide, we’ll walk through implementing this feature using MongoDB, Node.js, Express, and JWT (JSON Web Token).

Prerequisites
Before we begin, ensure you have:

  • Node.js & npm installed
  • MongoDB set up (local or cloud-based like MongoDB Atlas)
  • Basic knowledge of Express & JWT

Step 1: Set Up Your Project
Initialize a new Node.js project:

mkdir forgot-password && cd forgot-password
npm init -y
Enter fullscreen mode Exit fullscreen mode

Install required dependencies:

npm install express mongoose dotenv jsonwebtoken bcryptjs nodemailer cors body-parser
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure MongoDB & Express
Create an .env file to store database credentials:

MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_jwt_secret
EMAIL_USER=your_email@example.com
EMAIL_PASS=your_email_password

Enter fullscreen mode Exit fullscreen mode

Set up Express and MongoDB connection in server.js:

const express = require("express");
const mongoose = require("mongoose");
require("dotenv").config();

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

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 the User Model
Define a User schema in models/User.js:

const mongoose = require("mongoose");

const UserSchema = new mongoose.Schema({
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    resetToken: { type: String, default: null },
    resetTokenExpiry: { type: Date, default: null }
});

module.exports = mongoose.model("User", UserSchema);

Enter fullscreen mode Exit fullscreen mode

Step 4: Implement the Password Reset Flow
1️⃣ Generate Reset Token
Create an endpoint in routes/auth.js to send a reset email:

const express = require("express");
const User = require("../models/User");
const jwt = require("jsonwebtoken");
const nodemailer = require("nodemailer");

const router = express.Router();

router.post("/forgot-password", async (req, res) => {
    const { email } = req.body;
    const user = await User.findOne({ email });

    if (!user) return res.status(404).json({ message: "User not found" });

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

    user.resetToken = token;
    user.resetTokenExpiry = Date.now() + 3600000; // 1 hour
    await user.save();

    // Email setup
    const transporter = nodemailer.createTransport({
        service: "gmail",
        auth: {
            user: process.env.EMAIL_USER,
            pass: process.env.EMAIL_PASS
        }
    });

    const mailOptions = {
        to: user.email,
        subject: "Password Reset",
        text: `Click the link to reset your password: http://localhost:3000/reset-password/${token}`
    };

    await transporter.sendMail(mailOptions);

    res.json({ message: "Reset link sent to email" });
});

module.exports = router;

Enter fullscreen mode Exit fullscreen mode

2️⃣ Reset Password
Create an endpoint to reset the password:

router.post("/reset-password", async (req, res) => {
    const { token, newPassword } = req.body;

    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const user = await User.findOne({ _id: decoded.id, resetToken: token });

        if (!user || user.resetTokenExpiry < Date.now()) {
            return res.status(400).json({ message: "Invalid or expired token" });
        }

        user.password = require("bcryptjs").hashSync(newPassword, 10);
        user.resetToken = null;
        user.resetTokenExpiry = null;
        await user.save();

        res.json({ message: "Password reset successful" });
    } catch (err) {
        res.status(400).json({ message: "Invalid token" });
    }
});

module.exports = router;

Enter fullscreen mode Exit fullscreen mode

Step 5: Test the Implementation
Send a POST request to /forgot-password with { "email": "user@example.com" }.
Check your email for the reset link.
Send a POST request to /reset-password with { "token": "received_token", "newPassword": "new_secure_password" }.

Conclusion
You’ve successfully implemented a secure password reset feature with MongoDB, Node.js, and Express. This approach ensures security by validating tokens, hashing passwords, and setting expiration times.

🚀 Next Steps? Implement front-end integration and improve security with rate limiting and better email templates!

Top comments (0)