[Fixed] How do we hash a put request password?

Issue

Hi everyone am trying to hash my put request using bcrypt in my express-mongoose server

the put request

// updating  a user
router.put('/:id', async (req, res) => {
    const {error} = validate(req.body)
    if (error) return res.status(400).send(error.details[0].message)

    const user = await User.findByIdAndUpdate(req.params.id, {
        $set : {
            name: req.body.name,
            email: req.body.email,
            password: req.body.password
        }
    })
    // hashing user passwords
    const salt = await bcrypt.genSalt(10)
    user.password = await bcrypt.hash(user.password, salt)

    if (!user) return res.status(404).send('User with that id does not exist')
    
    
    res.send(user)
})

All other functions inside the update request is working perfectly apart from hashing the updated password. As a newbie I need your help/ best approach recommendation in this.
Thanks in advance…

Solution

Solution 1: Easy Way

For your personal solution, without really modifying the code, it works like the following.

// updating  a user
router.put('/:id', async (req, res) => {
    const {error} = validate(req.body)
    if (error) return res.status(400).send(error.details[0].message)

    // Why not make the hash function here?
    const salt = await bcrypt.genSalt(10)
    const newPassword = await bcrypt.hash(req.body.password, salt)

    const user = await User.findByIdAndUpdate(req.params.id, {
        $set : {
            name: req.body.name,
            email: req.body.email,
            password: newPassword
        }
    })

    if (!user) return res.status(404).send('User with that id does not exist')
    
    
    res.send(user)
})

You have a mistake in your user.password call. The findByIdAndUpdate method does not return an object that you can modify instantly. In above workaround, we simply move the function so that it hashes the new password first before updating your document.

Solution 2: My Own Style

For my personal solution, I’d go like this. Let’s say that you have a userModel that stores the schema of your User entity. I will add a new middleware that will run every time the password changes.

/** your user schema code. **/

userSchema.pre('save', async function (next) {
  // Only run the encryption if password is modified.
  if (!this.isModified('password')) {
    return next();
  }

  // Hash the password with BCRYPT Algorithm, with 12 characters of randomly generated salt.
  this.password = await bcrypt.hash(this.password, 12);
  next();
});

Next, we’ll create a new dedicated route in order to handle password changes. I think it’s better if we define a new route for it as passwords are sensitive data. Below is pseudocode, don’t instantly copy and paste it, it wouldn’t work.

const user = await User.findById(...);
user.password = req.body.password;
await user.save({ validateBeforeSave: true });

Remember that save middleware runs every time after the save command is run.

Further reading about Mongoose’s middlewares here.

Leave a Reply

(*) Required, Your email will not be published