Next.js Discord

Discord Forum

bcrypt.compare() always returns false

Answered
Spotted Rail posted this in #help-forum
Open in Discord
Spotted RailOP
So i have run into an issue with bcrypt import. It is imported in my /auth.js file and auth is imported in middleware file which throws an error of node-gyp. If I remove the import the error is gone. I am also importing bcrypt in server actions, but no errors there.
Error:
./node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
Answered by Anay-208
Summary:
- You can't use bcrypt in middleware as middleware is executed as a edge function
- the fact you were getting false in check is because of invalid password, because the discordId was null in the document of jack@gmail.com, which returned that instead of user@gmail.com
View full answer

151 Replies

you can use bcrypt in middleware
as middlware is edge function
and bcrypt doesn't work on edge function
Spotted RailOP
but it is causing errors
The simple explaination is that you can't just bcrypt in middleware.

Even if you import from a file which uses bcrypt, it'll cause the error
Spotted RailOP
So what can I do
Are you using any function related to bcrypt in middleware?
Spotted RailOP
middleware.js
import { auth } from "./auth";
import {
    authRoutes,
    DEFAULT_REDIRECT_LOGIN_URL,
    DEFAULT_REDIRECT_HOME_URL
} from './routes';

export default auth((req) => {

    const url = req.nextUrl;
    const route = req.nextUrl.pathname;

    const isLoggedIn = !!req.auth;

    console.log(route);

    function checkAuthRoute(authRoute) {
        if (route.startsWith(authRoute)) {
            return true;
        }
        return null;
    }

    console.log(!!authRoutes.filter(checkAuthRoute).length);

    if (!!authRoutes.filter(checkAuthRoute).length) {
        if (isLoggedIn) {
            return Response.redirect(new URL(DEFAULT_REDIRECT_HOME_URL, url));
        }
        return null;
    }

    if (route.startsWith(...authRoutes)) {
        if (isLoggedIn) {
            return Response.redirect(new URL(DEFAULT_REDIRECT_HOME_URL, url));
        }
        return null;
    }

    if (!(route === "/" || route === "/signin" || route === "/signup")) {
        if (!isLoggedIn) {
            return Response.redirect(new URL(DEFAULT_REDIRECT_LOGIN_URL, url));
        }
        return null;
    }

    return null;

})

export const config = {
    matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
Can I see the auth function?
Spotted RailOP
auth.js
import NextAuth from 'next-auth';
import { connectToDatabase } from "@/app/utils/db";
import CredentialsProvider from 'next-auth/providers/credentials';
import DiscordProvider from "next-auth/providers/discord";
import Users from "@/app/lib/user.model";

export const { handlers: { GET, POST }, auth, signIn, signOut } = NextAuth({
    providers: [
        CredentialsProvider({
            credentials: {
                email: { label: "Email", type: "email" },
                password: { label: "Password", type: "password" }
            },
            async authorize(credentials) {
                await connectToDatabase();
                const user = await Users.findOne({
                    $or: [{ email: credentials.email }, { discordId: credentials.discordId }],
                });

                console.log(credentials);

                if (user && user.password) {
                    const bcrypt = require("bcrypt");
                    // If email login, verify password
                    const hashPass = /^\$2y\$/.test(user.password) ? '$2a$' + user.password.slice(4) : user.password
                    // const passwordsMatch = true;
                    const passwordsMatch = await bcrypt.compare(credentials.password, hashPass);
                    console.log("pw", passwordsMatch);
                    if (passwordsMatch) {
                        console.log("yep they match");
                        return user;
                    } else {
                        console.log("Passwords do not match");
                        return null;
                    }
                } else if (user && user.discordId) {
                    // Existing Discord user, return user data
                    return user;
                }

                return null;
            }
        }),
    
couldnt send full code due to message limitation
Ya, this is because this file using bcrypt and its causing the error
https://www.npmjs.com/package/bcryptjs

can you try this package?
Spotted RailOP
I have tried bcryptjs, but there is one issue, it's compare function always returns true. Also it is no longer being maintained
simpleecrypt?
@Anay-208 simpleecrypt?
Spotted RailOP
seems dead, last update 11 years ago :Skull:
try with the crypto module using this:
// Using the built in crypto module

const { scryptSync, randomBytes } = require("crypto");


// Any random string here (ideally should be atleast 16 bytes)

const salt = randomBytes(16).toString("hex")


// Pass the password string and get hashed password back
// ( and store only the hashed string along with the salt in your database)
// {hashedPassword}${salt}

const getHash = (password) => scryptSync(password, salt, 32).toString("hex");
use import instead of const
Spotted RailOP
i am using bcrypt.hash while creating user, will it be compatible with this?
Why not try it out?
Spotted RailOP
ok
is your issue resolved?
Spotted RailOP
nope
i think i'll have to refactor my logic
Once done, send the solution here and mark it as solution
@Anay-208 Once done, send the solution here and mark it as solution
Spotted RailOP
i tried refactoring and using crypto, not working :sadCat:
I'll give you a solution when I get free, I'll try it in my own env
Spotted RailOP
If i could just separate the password comparing logic smw else
also, if your issue is resolved, Let me know, As if it is resolved, I won't test it.
since you're trying a different solution
Spotted RailOP
ya i'll post it as soon I get it working
Spotted RailOP
Okay @Anay-208 I decided to let go of middleware file, but now a new issue arise
bcrypt.compare() always returns false! even if the password is correct
Can you send dependencies of your package.json? I'm currently opening a playground for testing it
Spotted RailOP
sure,
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"argon2": "^0.40.1",
"bcrypt": "^5.1.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"mongoose": "^8.3.3",
"next": "14.1.0",
"next-auth": "^5.0.0-beta.13",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.51.4",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "^14.1.0",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.3"
}
alright, will try in a few mins
Spotted RailOP
ty
Iridescent shark
@Spotted Rail let me clear some stuff up for you
first off, no, middlewares are not edge functions
edge functions are basically small pieces of code that run in the cloud on a network for global reach
bcrypt has nothing to do with the edge
Spotted RailOP
alright
Iridescent shark
second off, try using the built in crypto node standard library
i dont know if it actually works in the cloud or not because some edge providers use a custom runtime
but try it
it might work
@Spotted Rail i tried, already
Iridescent shark
import error as well?
Spotted RailOP
yes
Iridescent shark
does it just say module or file not found?
damn
okay
gimme one sec
Spotted RailOP
i have ditched middleware
Iridescent shark
@Spotted Rail i have ditched middleware
Iridescent shark
dw, middleware isnt the issue here
@Iridescent shark i dont know if it actually works in the cloud or not because *some* edge providers use a custom runtime
middleware always run on the edge runtime, which does not work with "crypto" node module. it only works with these browser crypto apis: https://nextjs.org/docs/app/api-reference/edge#crypto-apis
@Iridescent shark https://www.npmjs.com/package/bcrypt
Iridescent shark
seems pretty up-to-date
well, middleware is the issue
@joulev well, middleware *is* the issue
Iridescent shark
true
lets just try using an npm package and pray 🙏
@joulev middleware always run on the edge runtime, which does not work with `"crypto"` node module. it only works with these browser crypto apis: https://nextjs.org/docs/app/api-reference/edge#crypto-apis
grab a package that works on the browser, then it should work in edge. grab a package that relies on nodejs apis then it most likely won't work on edge. middleware always runs on edge
nevermind it does not
Cape lion
That doesn't because the node.js bcrypt is pretty much a c++ addon
And they don't tend to work on edge
@Cape lion That doesn't because the node.js bcrypt is pretty much a c++ addon
Iridescent shark
+ it uses node apis
its stated in the package's description
so yeah
@Cape lion And they don't tend to work on edge
Iridescent shark
yep, since its a constrained environment
hmmm
if it is somehow possible for you not to do this client-side
that would be good
but we'll find packages
that work client-side
Spotted RailOP
like i said I have now removed middleware file from my project, the problem is bcrypt.compare(), it always return false
Cape lion
So, the .hash function works just fine, but the .compare function doesn't?
Spotted RailOP
yes
@Spotted Rail I'm using bcryptjs, and its working just fine
code:
import bcrypt from 'bcryptjs';

export async function GET(){
    const data = await bcrypt.hashSync("hello", 8)
    console.log(data)
    const compare = await bcrypt.compareSync("hello", data)
    const compare2 = await bcrypt.compareSync("hell", data)

    console.log(compare, compare2)
    return new Response("hello")
}
console
I'm using nextjs 14.2.3
Spotted RailOP
what diff between hash and hashSync?
i am using .hash()
@Anay-208 I'm using nextjs 14.2.3
Spotted RailOP
this version has a middleware redirect issue, u get redirected but the url in your browser stays the same until u reload it
@Spotted Rail what diff between hash and hashSync?
with hashSync, you won't need to use await(I might have used await mistakenly)
I'll downgrade to 14.1.0
and test
also @Spotted Rail So the solution is to use bcryptjs. it should work
also working with 14.1.0
Spotted RailOP
Ok ill first try swtiching to bcryptjs
If that works, mark the message as a solution, otherwise ping me
@Anay-208 If that works, mark the message as a solution, otherwise ping me
Spotted RailOP
hasn't worked, im gonna try signing up with a new user and try again
yeah, didn't work
Share your code, and also, create a min repro repo
Spotted RailOP
@Anay-208
Sure I’ll check
@Spotted Rail I need a min repro repo only
Spotted RailOP
Oh ok, I'll have to make one I see
@Spotted Rail so the problem seems to be when I store it mongodb and compare it
I've used [next-mongodb-api](https://npmjs.com/package/next-mongodb-api) once in a production project for authentication, and it works just fine!
(package is made by me)
are you sure mongodb driver is returning the right output
console.log it
@Anay-208 are you sure mongodb driver is returning the right output
Spotted RailOP
yes, when the logs shows exact hash that is stord in DB
With mongodb Driver, I have faced a lot of issue because of the return types
Spotted RailOP
i am using mongoose only
try converting it to a pure object
@Anay-208 try converting it to a pure object
Spotted RailOP
how
@Spotted Rail i am using mongoose only
I also used mongoose, I faced a issue, which I was so confused on how to fix
I just had to add the method .toObject() on the return type
Spotted RailOP
alright leme try it quickly
just to be clear, I need to convert hash into an object?
Spotted RailOP
@Anay-208 just logged the hash and compared, they are a bit different actually, could that be an issue?
@Spotted Rail just to be clear, I need to convert hash into an object?
Spotted RailOP
not sure how i do this, i did console.log(user.password.toObject()) this throws an err
Spotted RailOP
ohh i got the issue
no matter what credentials i put, always the first user gets returned
Is this a correct way to find a user?
const user = await Users.findOne({ $or: [{ email: credentials.email }, { discordId: credentials.discordId }], });
the object returned from mongodb
@Spotted Rail no matter what credentials i put, always the first user gets returned
Spotted RailOP
this is the issue @Anay-208
@Spotted Rail this is the issue <@755810867878297610>
console.log credentials.email
@Anay-208 console.log `credentials.email`
Spotted RailOP
that's user@gmail.com, but I always get the jack's record, is my query wrong?
does user@gmail.com exist on the db?
it could be because discordId is null
@Anay-208 does user@gmail.com exist on the db?
Spotted RailOP
@Anay-208 it could be because discordId is null
Spotted RailOP
that's why I have used $or
@Anay-208 it could be because discordId is null
Spotted RailOP
you are right
I removed discordId from the array it worked
Spotted RailOP
@Anay-208 Thanks a ton for helping me throughout this. :ASnekobow: Not sure what should I mark as an answer XD
Spotted RailOP
I have something to send to, which might be helpful
for others
Summary:
- You can't use bcrypt in middleware as middleware is executed as a edge function
- the fact you were getting false in check is because of invalid password, because the discordId was null in the document of jack@gmail.com, which returned that instead of user@gmail.com
Answer
You can mark the above message as a solution
Spotted RailOP
Spotted RailOP
Yes, thats why I told you bcrypt doesn't work on middleware