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);
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.