skip to Main Content

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.

Hashed password added on mongodb

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


  1. Chosen as BEST ANSWER

    Login logic was completely correct, but I had wrong User model like following:

    const userSchema = new mongoose.Schema({
      email: {
        type: String,
        required: true,
        lowercase: true
      },
      password: {
        type: String,
        required: true,
        lowercase: true  //remove this to make it work
      }
    });
    
    
    

    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...


  2. 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 and bcrypt.compare methods. If you want to use await bcrypto.compare(...), create your hash using:

    await bcrypt.hash(password, 10);

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search