2
votes

I am a complete beginner in coding, currently learning NodeJs and i am stuck with this situation for days now. I am trying to compare the hashed password in my mongodb with the users input through postman. I am using bcrypt to compare the hashed password with the original string but i am getting false statement. Any help is much appreciated

This is the mongoose model Schema,

const usersSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true,
  },
  email: {
    type: String,
    unique: true,
    required: true,
    lowercase: true,
    validate(value) {
      if (!validator.isEmail(value)) throw new Error("Invalid email");
    },
  },
  password: {
    type: String,
    required: true,
    trim: true,
    minLength: 7,
    validate(value) {
      if (value.toLowerCase().includes("password")) {
        throw new Error("Password should not consist of string 'password'.");
      }
    },
  },
})

Right here I hash the password before saving to the database;

usersSchema.pre("save", async function (next) {

  const user = this;
  const saltRounds = 8;

  if (user.isModified("password")) {
    user.password = await bcrypt.hash(user.password, saltRounds);
  }

  next();
});

Below is the login route;

router.post("/users/login", async (req, res) => {
  try {
    const user = await Users.findByCredentials(
      req.body.email,
      req.body.password
    );

    res.send(user);
  } catch (error) {
    res.status(400).send(error);
  }
});

Below is where I try to compare the passwords, help me figure out why I am getting false.

usersSchema.statics.findByCredentials = async (email, password) => {
  const user = await Users.findOne({ email: email });

  if (!user) {
    throw new Error("Unable to log in!");
  }

  const isMatch = await bcrypt.compare(password, user.password);

  if (!isMatch) {
    throw new Error("Unable to login");
  }

  return user;
};
2
I wonder, how do you save and update the user. There is one problem with your "save" hook. The "save" hook will not be executed on update and findOneAndUpdate. So when the password is updated it won't be hashed. You should use other hooks like updateOne or findOneAndUpdate. - Boris Kukec
I have tried changing the hook findOne to findOneAndUpdate but the result is still the same false. - Kleva_ Saki
And it seems like bcrypt is producing a different hash everytime, even if i feed it the same string. so this will never match. - Kleva_ Saki
just console.log password and user.password before comparing and ensure the values are what you expect them to be. This way you can narrow down the problem - disjunction
Yes these values are dfferent and dont understand why? console.log(user.password) // $2a$08$hnfxw2ws.jznauegxrrty.mlrfcwjkatwb/a580lbeu51gvzbzvyi console.log(await bcrypt.hash(password, 8)) // $2a$08$7fd4NhW6lV2AbsmCf7N20OyvguGZslFukafqS6mk2QYMeVYtUH6jW - Kleva_ Saki

2 Answers

1
votes

when ever you use bcrypt it works with you password property on your model In this case you dont want to trim or lower case any properties of password. So when designing Schema we dont want to over-load password with extra validations.We have to work with minimal validations in order for bcrypt to function properly.I had the same issue i removedlowerCase:true,trim:true from the Schema then it worked. try to remove extra validations or restriction from password other wise it will interfere with bcrypt compare function.

0
votes

try using bcryptjs.hashSync() and bcryptjs.compareSync instead