error: data and hash arguments required for bcrypt. Incorrect MongoDB setup

Viewed 487

I am trying to set up Passport with Express and MongoDB. At the moment I am able to register users in the database. But whenever I try to login, I get an error saying that data and hash arguments are required. Right now I have my Server.js file like this

const mongoose = require('mongoose');
const User = require('./models/users')

     const initializePassport = require('./passport-config')
      initializePassport(
        passport,
        email => User.find({email: email}),
        id => User.find({id: id})
      )


      app.post('/register', checkNotAuthenticated, async (req, res) => {
        try {
          const hashedPassword = await bcrypt.hash(req.body.password, 10)
          const newUser = new User({
            id: Date.now().toString(),
            name: req.body.name,
            email: req.body.email,
            password: hashedPassword
          })
          res.redirect('/login')
          console.log(newUser)
        } catch {
          res.redirect('/register')
        }

    And my Passport-Config.js file like this `

    const LocalStrategy = require('passport-local').Strategy
    const bcrypt = require('bcrypt');
    const User = require('./models/users')

    function initialize(passport, getUserByEmail, getUserById) {
      const authenticateUser = async (email, password, done) => {
        const user = getUserByEmail(email)
        if (user === null) {
          return done(null, false, { message: 'No user with that email' })

        }

        try {
          if (await bcrypt.compare(password, user.password)) {
            return done(null, user)
          } else {
            return done(null, false, { message: 'Password incorrect' })
          }
        } catch (e) {
          return done(e)
        }
      }

      passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
      passport.serializeUser((user, done) => done(null, user.id))
      passport.deserializeUser((id, done) => {
        return done(null, User.findById({user: id}))
      })
    }

    `
1 Answers

I've done some investigation using console.log() statements (not proud of it) but I think I've managed to find out the issue. If we add in the the first console log statement here:

  app.post('/register', checkNotAuthenticated, async (req, res) => {
    try {
      console.log("BCRYPT COMPARE RUNS HERE")
      const hashedPassword = await bcrypt.hash(req.body.password, 10)
      const newUser = new User({
        id: Date.now().toString(),
        name: req.body.name,
        email: req.body.email,
        password: hashedPassword
      })
      res.redirect('/login')
      console.log(newUser)
    } catch {
      res.redirect('/register')
    }

and the second one here:

 const initializePassport = require('./passport-config')
  initializePassport(
    passport,
    email => User.find({email: email}).then((result) => { console.log("USER DATA EXTRACTED HERE") }).catch((err) => { console.log(err) }),
    id => User.find({id: id})
  )

The next time you click on login, you should see an output like:

Listening on port 3000
BCRYPT COMPARE HAPPENING
Error: data and hash arguments required
...
...
...
USER DATA EXTRACTED HERE

Notice that bcrypt.compare is being run before we are actually able to grab the user information from the DB? This means that all the arguments into that function are null, which is what is returning that error. Now, I'm no JS expert, but this can be fixed with an await statement added here:

   function initialize(passport, getUserByEmail, getUserById) {
      const authenticateUser = async (email, password, done) => {
        const user = await getUserByEmail(email)
        if (user === null) {
          return done(null, false, { message: 'No user with that email' })

        }

Which makes sure that the user info is queried from the DB before moving along in the script.

Related