Bcrypt + Sequelize password not saving as hash in DB

Viewed 3200

Sequelize + Bcrypt not storing passwords in DB as hash

As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.

Model

// const Promise = require('bluebird')
const bcrypt = require('bcrypt')

async function hashPassword (user, options) {
  if (!user.changed('password')) {
    return 0
  }
  const SALT_FACTOR = 8
  await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
    if (err) {
      console.log(err)
    }
    // user.setDataValue('password', hash)
    user.password = hash
    console.log(user)
  })
}

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    email: {
      type: DataTypes.STRING,
      unique: true
    },
    password: DataTypes.STRING
  }, {
    hooks: {
      beforeSave: hashPassword,
      beforeCreate: hashPassword
    }
  })

  User.prototype.comparePassword = function (password) {
    bcrypt.compare(password, this.password, function (res, err) {
      if (res) {
        console.log(res)
      } else {
        console.log(err)
      }
    })
    return bcrypt.compare(password, this.password)
  }

  return User
}

Controllers

module.exports = {
  async register (req, res) {
    try {
      const user = await User.create(req.body)
      const userJson = user.toJSON()
      res.send({
        user: userJson,
        token: jwtSignUser(userJson)
      })
    } catch (err) {
      // e-mail already exists or such
      res.status(400).send({
        error: 'This email address is already in use'
      })
    }
  },
  async login (req, res) {
    try {
      // Grab user input
      const { email, password } = req.body
      const user = await User.findOne({
        where: {
          email: email
        }
      })
      // Check to see if user is in db
      if (!user) {
        res.status(403).send({
          error: 'the login information was incorrect / Not Found'
        })
      }
      // Check to see if password is valid
      const isPasswordValid = await user.comparePassword(password)
      if (!isPasswordValid) {
        return res.status(403).send({
          error: 'The login information was incorrect'
        })
      }
      // return user using toJSON()
      const userJson = user.toJSON()
      res.send({
        user: userJson,
        token: jwtSignUser(userJson)
      })
    } catch (e) {
      res.status(500).send({ error: 'An error occured attempting to login' })
      console.log(e)
    }
  }
}

To elaborate a little more, whenever I create a user, I receive the following:

{
    "user": {
        "id": 1,
        "email": 'test@test.com",
        "password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
        "updatedAt": "2018-09-07T22:44:12.944Z",
        "createdAt": "2018-09-07T22:44:12.944Z"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}

Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!

2 Answers

I'm pretty sure that this answer is too late for you, but might help others landing on this same question.

The main issue I can see is how you are using the async/await pattern. Changing this:

async function hashPassword (user, options) {
  if (!user.changed('password')) {
    return 0
  }
  const SALT_FACTOR = 8
  await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
    if (err) {
      console.log(err)
    }
    // user.setDataValue('password', hash)
    user.password = hash
    console.log(user)
  })
}

to this, worked for me:

async function hashPassword(user, options) {
  if (!user.changed("password")) {
    return 0;
  }
  user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}

Can you please try to add only one hook

hooks: {
      beforeSave: hashPassword,
    }

Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.

Hope it helps

Related