0

I am first time making APIs about forgot password and then reset password. I am facing strange issue. There is not a single error, it gives me success status that password is updated. The problem is that in my database password is NOT updated.

User schema:

const UserSchema = new mongoose.Schema({
  email: { type: String, required: true, min: 6, max: 255 },
  password: { type: String, required: true, min: 4, max: 1024 },
  resetLink: { data: String, default: "" },
});
module.exports = mongoose.model("Users", UserSchema);

Forgot password: (when user click forgot password and writes an email, this happens:

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

    //check if user is alredy in database
    const user = await User.findOne({ email: req.body.email });
    if (!user) return res.status(400).send("User doesn't exist");

    // create token
    const token = jwt.sign({ email: user.email, _id: user._id }, secretKey, {
      expiresIn: "15m",
    });

    // generate resetUrl link using the token and id
    const link = `http://localhost:3000/api/users/reset-password/${user._id}/${token}`;

    res.send("password reset link has been sent to an email");

    // SEND EMAIL
    let transporter = nodemailer.createTransport({
      host: "*******",
      port: 587,
      secure: false,
      auth: {
        user: "*******",
        pass: "*******",
      },
    });
    let info = transporter.sendMail({
      from: '"Reset password" <*********>', // sender address
      to: req.body.email, // list of receivers
      subject: "Hello", // Subject line
      html: `<p>Visit the: ${link}</p>`,
    });

    user.updateOne({ resetLink: token });
  } catch (err) {
    res.status(400).json(err);
  }
});

Change password process Firstly get method

router.get("/reset-password/:id/:token", async (req: any, res: any) => {
  const { id, token } = req.params;

  // Check if ID is valid
  const user = await User.findOne({ _id: id });
  if (!user)
    return res.status(400).send("User doesn't exist");

  try {
    const verify = jwt.verify(token, secretKey);
    res.render("reset-password", { email: user.email });
  } catch (err) {
    res.status(400).json(err);
  }
});

And then post method

router.post("/reset-password/:id/:token", async (req: any, res: any) => {
  const { id, token } = req.params;
  const { password } = req.body.password;
  const { password2 } = req.body.password2;

  // Validate if user is alredy in database
  const user = await User.findOne({ _id: id });
  if (!user) return res.status(400).send("User doesn't exist");

  try {
    const verify = jwt.verify(token, secretKey);
    // validate if password 1 and password 2 MATCH -> NOT YET

    // Update password
    const password = req.body.password2;
    bcrypt.genSalt(saltRounds, (err: any, salt: any) => {
      if (err) return res.json(err);
      bcrypt.hash(password, salt, async (err: any, hash: any) => {
        await user.save({ password: hash });
        res.send("Password is updated!");
      });
    });
  } catch (err) {
    res.status(400).json(err);
  }
});

And I would alse be very happy, if someone could tell me or give me an advice, if there should me some changed regards to better security.

Update: I will be using then Angular for frontend, so I am not even sure, if the get method in change password is needed (where i just make res.render("reset-password", { email: user.email }); ) An explanation of this line would be perfect

Thanks to everyone!

3
  • user.save({ password: hash }); returns an promise, you could try to await it Commented Jun 11, 2022 at 12:53
  • I did, and it still doesn't update password in my database :/ Commented Jun 11, 2022 at 13:00
  • You should sanitize the user input, see npmjs.com/package/mongo-sanitize Commented Jun 11, 2022 at 14:11

1 Answer 1

1

Try to pass password2 to the hash function instead of generating a new variable and change the way you set the new password.
Plus, you should await the save() function:

router.post("/reset-password/:id/:token", async (req: any, res: any) => {
  const { id, token } = req.params;
  const { password, password2 } = req.body;

  // Validate if user is alredy in database
  const user = await User.findOne({ _id: id });
  if (!user) return res.status(400).send("User doesn't exist");

  try {
    const verify = jwt.verify(token, secretKey);
    // validate if password 1 and password 2 MATCH -> NOT YET

    // Update password
    bcrypt.genSalt(saltRounds, (err: any, salt: any) => {
      if (err) return res.json(err);
      bcrypt.hash(password2, salt, async (err: any, hash: any) => {
        user.password = hash
        await user.save()
        res.send("Password is updated!");
      });
    });
  } catch (err) {
    res.status(400).json(err);
  }
});
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, strangly after this I am getting error in my terminal: ValidationError: Users validation failed: password: Path password is required.
There was an error with req.body destructuring, see edited answer.
Thank you! It solved my problem. Now it is getting updated. May I just ask you this: Why is firstly needed the get method in change password process and what does res.render("reset-password", { email: user.email }); do? Do I even need this in MEAN stack application? because I am not sure if I will do any rendering like that way
I assume you do need the res.render(). It looks to me as the code responsible for sending the HTML template of the page for resetting the password. I think you could remove the res.render() if you implement the reset-password route in your Angular app.
I removed whole router.get("/reset-password/:id/:token") {} and it still works fine. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.