kelektiv / node.bcrypt.js

bcrypt for NodeJs
MIT License
7.43k stars 510 forks source link

bcrypt.compare always returns false #906

Open francis-Paul-code opened 2 years ago

francis-Paul-code commented 2 years ago

Of course many have had the challenge but I've looked at most solutions and I still can't find the reason why my case has refused.

Screenshot from 2021-12-13 20-12-22

I've checked everything thoroughly, the characters saved in the DB are the exact Hash character length, the passwords are the same, I just cannot understand why It refuses to work

jonbito commented 2 years ago

Ensure you aren't hashing more than once. Are you hashing in an ORM model update?

irkhamissimo commented 2 years ago

This might be happened because of character length in your DB. Check this

edersonfaccin commented 1 year ago

In my case, happened using windows, but the same project using a mac, works

Any solution?

Gatharikih commented 1 year ago

I'm also experiencing the same issue. The problem is neither due to rehashing nor using different character sets.

borjamunozvw commented 1 year ago

Here I'm facing the same problem with compareSync (is always returning false). But, in my case, when I change compareSync with compare, return true in every case.

image

mosesrb commented 1 year ago

I am having the same issue, anyone got the around it?

Gatharikih commented 1 year ago

Personally I'd to create a REST API in Java to hash and compare passwords.

borjamunozvw commented 1 year ago

For me the solution was to hashing the password and then compare it. It seems that the bycrypt.compare only works with the original password and the hashed pasword:

 if (!user) {
    console.log("user not found");
    return res.send("user not found!");
  } else {
    bcrypt.hash(req.body.password, 10, function (err, hash) {
      if (err) {
        throw err;
      } else {
        bcrypt.compare(user.password, hash, function (err, result) {
          if (err) {
            throw err;
          }
          console.log(result);
          if (!result) {
            return res.status(201).json({ message: "Wrong password!" });
          } else {
            return res.status(201).json({ message: "Connected!", user: user });
          }
        });
      }
    });
  }
mosesrb commented 1 year ago

For me the solution was to hashing the password and then compare it. It seems that the bycrypt.compare only works with the original password and the hashed pasword:

 if (!user) {
    console.log("user not found");
    return res.send("user not found!");
  } else {
    bcrypt.hash(req.body.password, 10, function (err, hash) {
      if (err) {
        throw err;
      } else {
        bcrypt.compare(user.password, hash, function (err, result) {
          if (err) {
            throw err;
          }
          console.log(result);
          if (!result) {
            return res.status(201).json({ message: "Wrong password!" });
          } else {
            return res.status(201).json({ message: "Connected!", user: user });
          }
        });
      }
    });
  }

The code above takes the plaintext password and hashes it and then uses bcrypt compare method over it. So every password is a valid password because you are not testing it against the stored password in database but rather with user own password.

mosesrb commented 1 year ago

Something is up with my MongoDB idk, tried argon2 npm as well and even that package is unable to verify password from MongoDB, below is my password field schema, am i doing something wrong here before storing data in MongoDB

const userSchema = new mongoose.Schema({ name:{ type: String, minlength: 3, maxlength: 255, required: true }, email:{ type: String, minlength: 3, maxlength: 255, unique: true, required: true }, password:{ type: String, minlength: 3, maxlength: 1024, required:true }, isAdmin: Boolean });

borjamunozvw commented 1 year ago

For me the solution was to hashing the password and then compare it. It seems that the bycrypt.compare only works with the original password and the hashed pasword:

 if (!user) {
    console.log("user not found");
    return res.send("user not found!");
  } else {
    bcrypt.hash(req.body.password, 10, function (err, hash) {
      if (err) {
        throw err;
      } else {
        bcrypt.compare(user.password, hash, function (err, result) {
          if (err) {
            throw err;
          }
          console.log(result);
          if (!result) {
            return res.status(201).json({ message: "Wrong password!" });
          } else {
            return res.status(201).json({ message: "Connected!", user: user });
          }
        });
      }
    });
  }

The code above takes the plaintext password and hashes it and then uses bcrypt compare method over it. So every password is a valid password because you are not testing it against the stored password in database but rather with user own password.

Sorry that I didn't copy the full code so it the can be tricky. In my case "user.password" was the equivalent to my database user (as you can see, I've declared and array with users), and not the received through body (I also checked with postman). Here you can find the full code:


const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");

function login(req, res) {
  // console.log('username', req.body.username)
  // console.log('password', req.body.password)
  const users = [
    {
      id: "kasndaojsdnasd",
      username: "usuario1",
      password: "pwusuario1",
    },
    {
      id: "kasasdasdasd",
      username: "usuario2",
      password: "pwusuario2",
    },
    {
      id: "asdasdnasd",
      username: "usuario3",
      password: "pwusuario3",
    },
  ];
  //modify for the proper db service
  const user = users.find((user) => user.username == req.body.username);

  if (!user) {
    console.log("user not found");
    return res.send("user not found!");
  } else {
    bcrypt.hash(req.body.password, 10, function (err, hash) {
      if (err) {
        throw err;
      } else {
        bcrypt.compare(user.password, hash, function (err, result) {
          if (err) {
            throw err;
          }
          console.log(result);
          if (!result) {
            return res.status(201).json({ message: "Wrong password!" });
          } else {
            return res.status(201).json({ message: "Connected!", user: user });
          }
        });
      }
    });
  }
}

module.exports = login;

I've tested with both correct and incorrect password and username and works in every case

recrsn commented 1 year ago

@borjamunozvw your code here is incorrect; bcrypt expects compare(data, hash)

For others with this issue, unless someone provides me with a sample repository and some DB dump, I'll not be able to work on this case. I'm unable to reproduce this at my side.

mosesrb commented 1 year ago

@borjamunozvw Yes you are right the 'user' is from database, however the

bcrypt.compare() require plaintext and hash password from database.

bcrypt.compare(plaintext, hashpassword)

and i also tried your code but it's still giving me false every time.

mosesrb commented 1 year ago

@recrsn I am using node@16.14.2 along with mongoose@6.9.1 with mongoDB compass. I have no idea why compare method is not working. I tried argon2 npm as well. The verify method in that package is also not working with my setup.

I think something is wrong with my database, I have increased the limit to 2048 char for password but still it's not working

SuhailHamid42 commented 1 year ago

I had also same problem and finally I realised that we first have to save the one user and password will be encrypted and then compare will work properly. I did it and my problem was solved. If you have users in the db whose passwords aren't encrypted then compare will always return false.

Gatharikih commented 1 year ago

I had also same problem and finally I realised that we first have to save the one user and password will be encrypted and then compare will work properly. I did it and my problem was solved. If you have users in the db whose passwords aren't encrypted then compare will always return false.

For avoidance of doubt, am comparing user's encrypted password stored in db against the user's provided password.

Forium777 commented 1 year ago

Same issue. Seems to always returns false. Database column is enough large, tried to change $2b$ to $2a$ without chance, tried to use compare() instead of compareSync() but all same. Still returning false...

Any workaround?

vamshizz commented 1 year ago

I had also same problem and finally I realised that we first have to save the one user and password will be encrypted and then compare will work properly. I did it and my problem was solved. If you have users in the db whose passwords aren't encrypted then compare will always return false.

for me same issue how to solve

PACMainArchitect commented 1 year ago

This might be happened because of character length in your DB. Check this

Thank's a lot, you saved my day

JLimaRodrigues commented 8 months ago

To resolve the issue, I observed that in the database, I was storing the password in a designated column with a character size smaller than the number of characters in the password hash. I simply made the change, and it worked.

noriaku commented 8 months ago

I was having the same error and apparently, as mentioned in this answer, it is an error in the database. In my case I had to define the maxlength to 60 in my MongoDB schema, I show you an example of what it looks like:

password: { type: String, required: true, unique: false, maxlength: 60 },

Hope it helps !!