Search code examples
node.jsmongodbmongoose

Incorrect new password with express and mongoose


I want to implement a controller that update the user's password.

Problem: When a user is created, I see in database that it is hashed correctly. When I try my controller (to update the password), I send the old password and the new one.
The first time it works fine. But then, if I put the new one in old, and set a new one I get error : "message": "Incorrect old password". Why ?

My controller :

module.exports.updatePassword = async (req, res) => {
  const { userId } = req.params;
  const { oldPassword, newPassword } = req.body;

  try {
    const user = await User.findById(userId);

    const isPasswordValid = await user.isValidPassword(oldPassword);

    if (!isPasswordValid) {
      return res.status(401).json({ message: "Incorrect old password" });
    }

    const salt = await bcrypt.genSalt(10);
    const newHashedPassword = await bcrypt.hash(newPassword, salt);
    const oldHashedPassword = user.password;

    if (oldHashedPassword === newHashedPassword) {
      return res
        .status(400)
        .json({
          message: "New password should not be the same as old password",
        });
    }

    user.password = newHashedPassword;
    await user.save();

    return res.json({ message: "Password updated successfully" });
  } catch (error) {
    console.error(error);
    return res.status(500).json({ message: "Server error" });
  }
};

My User Schema :

const mongoose = require("mongoose");
const bcrypt = require("bcrypt");

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: [true, "Provide an email."],
    unique: true,
    match: [
      /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/,
      "Please, provide a valid email.",
    ],
  },
  password: {
    type: String,
    required: [true, "Password is required."],
  },
  firstname: {
    type: String,
    required: [true, "Firstname is required."],
  },
  lastname: {
    type: String,
    required: [true, "Lastname is required."],
  },
});

UserSchema.pre("save", async function (next) {
  const user = this;
  const salt = await bcrypt.genSalt(10);
  const hash = await bcrypt.hash(user.password, salt);
  user.password = hash;
  next();
});

UserSchema.methods.isValidPassword = async function (password) {
  const user = this;
  const compare = await bcrypt.compare(password, user.password);

  return compare;
};

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

Solution

  • You already hash the password in pre save hook, so you don't need to hash it again in the updatePassword route.

    So changing user.password = newHashedPassword; to user.password = newPassword; should resolve the problem.