Search code examples
javascriptnode.jsasynchronoussequelize.jsbcrypt

How to execute bcrypt.compare inside Sequelize .then?


I'm trying to build a login page where I get the hashed password from mysql db using Sequelize and then calling bcrypt compare to dehash the password and compare it with the user's login input for authentication.

However, bcrypt compare is always executing slower than the return causing the value to always be "". I know this has to do with asynchronous behaviour but I don't know how to properly write this code to make it work.

     authenticate: (req, res) => {

    let userDetails = req.query;

    User.findOne({
      where: {
        username: userDetails.username
      }
    })
    .then((user) => {
      // How can I make this so, correctPassword() finishes
      // and then the authenticated variable will be either false or true?

      let authenticated = correctPassword(userDetails.password, user.password);
      return authenticated;
    })
    .then((authenticated) => {
      // right now authenticated is "" in client side console.

      res.send(authenticated);
    })
    .catch((error) => {
      console.log('there was an error: ', error);
    });
  }
}

const correctPassword = (enteredPassword, originalPassword) => {
  return bcrypt.compare(enteredPassword, originalPassword, (err, res) =>{
    return res;
  });
}

Solution

  • You're almost there. You correctly intuited that correctPassword executes asyncronously, though it is written as if it's syncronous.

    First off, let's make correctPassword a promise, so we can use async/await or call .then on it

    const correctPassword = (enteredPassword, originalPassword) => {
      return new Promise(resolve => {
        bcrypt.compare(enteredPassword, originalPassword, (err, res) =>{
          resolve(res)
        });  
      })
    }
    

    Next, you have two approaches to ensure the order of operations in your code executes correctly:

    (Recommended) Use async/await syntax allowing us to write synchronous-looking code:

    authenticate: async (req, res) => {
      let userDetails = req.query;
      try {
        const user = await User.findOne({
          where: {
            username: userDetails.username
          }
        });
    
        const authenticated = await correctPassword(userDetails.password, user.password);
    
        res.send(authenticated);        
      } catch(e) {
        res.status(400).send(e)
      }
    }
    

    Continue using promises:

    authenticate: (req, res) => {
      let userDetails = req.query;
      User.findOne({
        where: {
          username: userDetails.username
        }
      }).then(() => {
        correctPassword(userDetails.password, user.password)
          .then(authenticated => {
            res.send(authenticated)
          })
          .catch(e => {
            res.send(e)
          })
      })
    }