Bcrypt.compare returns false no matter what
I’m currently working on a login/register feature in NextJS that utilizes bcrypt to hash and compare user passwords. I’m able to register a user with a hashed password, but when attempting to log in with bcrypt.compare()
, the comparison always returns false, even when the entered password matches the hashed password.
The issue lies in this line: const isPasswordMatched = await bcrypt.compare(password, user.password);
, where the compare()
method is used to compare the entered password with the hashed password. Despite the method’s implementation, it’s not working as expected.
api/auth/[...nextauth].ts
for login
const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
async authorize(credentials, req) {
await connectDB();
const { email, password }: Icredential = credentials;
// Find user by email
const user = await User.findOne({ email: email });
if (user === null) {
throw new Error('Cannot find user');
}
// Check if password from input matches with the one from db
// This is the line of the concern
const isPasswordMatched = await bcrypt.compare(password, user.password);
console.log(`Comparing ${password} to ${user.password}`);
console.log("match ?", isPasswordMatched);
// Throw error when it doesn't
if (!isPasswordMatched)
// if (password !== '123')
{
throw new Error('Invalid email or password');
}
// Return authorized user
return user;
},
credentials: undefined
}),
],
};
export default NextAuth(authOptions);
api/register for register
const registerHandler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "POST") {
try {
const { user: _regiUser } = req.body;
console.log(_regiUser)
//Check if user exists
await connectDB()
const existingUser = await User.findOne({ email: _regiUser.email }).exec();
console.log("existingUser", existingUser);
//Throw error when email is already in use
if (existingUser) {
throw new Error("Email already used");
}
//Password encrypted
const hashedPassword: string = await bcrypt.hashSync( _regiUser.password, 10 );
console.log("_regiUser.password", _regiUser.password, hashedPassword)
console.log(hashedPassword)
//Replace text password with encrypted password
_regiUser.password = hashedPassword;
console.log(_regiUser)
//Add user on database
await User.create(_regiUser)
res.end()
} catch (e: any) {
console.log(e.message)
}
}
};
export default registerHandler;
2
Answers
Login logic was completely correct, but I had wrong User model like following:
look at password entity, because I copy pasted from email entity, i had a wrong configuration for password. So hash stored in lowercase and this is the very reason why i got error no matter what. smh...
You’re creating your password hashes using the
hashSync()
method (not async) but trying to run the async.compare()
method when logging-in. Check out the examples.For the comparison, you should be using:
bcrypt.compareSync(myPlaintextPassword, hash);
Otherwise, I recommend using the async/await
bcrypt.hash
andbcrypt.compare
methods. If you want to useawait bcrypto.compare(...)
, create your hash using:await bcrypt.hash(password, 10);