Skip to content

Reset password token with crypto in an Express app

I have this forgot password handler in my Express app. I send an email with a crypto.randomBytes(20).toString("hex") token, that I use later to verify the request. It is working perfectly.

However, I have seen that people are hashing this token before sending it and storing in the data base, and I don’t see why, cause it is already a random string.

const forgotPassword = async (req, res) => {
  try {
    const user = await User.findOne({ email: req.body.email });
    if (!user) {
      throw Error("incorrect email");
    }
    const resetPasswordToken = crypto.randomBytes(20).toString("hex");
    user.resetPasswordToken = resetPasswordToken;
    user.resetPasswordTokenExpire = Date.now() + 10 * (60 * 1000);
    await user.save();
    const message = `
      <h1>You have requested a password reset</h1>
      <p>Here is your token : </p>
      <p>${resetPasswordToken}</p>
    `;
    try {
      await sendEmail({
        to: user.email,
        subject: "Password reset request",
        text: message,
      });

      res.status(200).json({ message: "Email sent" });
    } catch (err) {
      user.resetPasswordToken = undefined;
      user.resetPasswordTokenExpire = undefined;
      res.status(500).json({ message: "Email could not be sent" });
    }
  } catch (error) {
    console.log(error);
    const errorDetails = handleErrors(error);
    res.status(400).json(errorDetails);
  }
};

Answer

If you hash the token and only save the hash into the database, you can make sure that admins and other people who are able to access the database cannot use the token to reset a password for a different user.

It’s basically the same reason, why you hash (and salt and pepper) passwords – because you don’t want, that the original string can be recreated whenever somebody has access to the table.