0

In my backend server which runs on express I have:

app.post("/login", async(req, res) => {
    try {
        const { username, password } = req.body;
        let result = await checkCredentials(username, password)
        console.log("result of checkCredentials:", result);
        res.json(result);
        
    } catch (error) {
        console.error(error);
    }
});

on post, the function checkCredentials get's called

const checkCredentials = async (clientUsername, clientPassword) => {
    try {
        const dbUsernameObj = await pool.query("SELECT varol_users_dealer_username FROM varol_users_dealers_credentials WHERE varol_users_dealer_username = $1", [clientUsername]);
        const dbUsername = dbUsernameObj.rows[0]?.varol_users_dealer_username
        const dbHashObj = await pool.query("SELECT varol_users_dealer_hash FROM varol_users_dealers_credentials WHERE varol_users_dealer_username = $1", [clientUsername])
        const dbHash = dbHashObj.rows[0]?.varol_users_dealer_hash

       // the 4 lines above are SQL queries that get the respective values, if they exist, if not they're undefined.


        if (dbUsername === clientUsername) {
            bcrypt.compare(clientPassword, dbHash, function(err, result) {
                if (err) {
                    console.log(err)
                }
                return result
            }); 
        } else {
            return false
        }
        
    } catch (error) {
        console.error(error);
    }
}

The problem with this code is, if I supply the right combination of username and password, when checkCredentials logs, it returns undefined. if my password is wrong, it also returns undefined.

But when my username is wrong, it returns false.

I believe the issue lays in promise chaining, since bcrypt.hash returns another promise, and the value of checkCredentials get's logged before bcrypt finishes.

How can I solve this issue? many thanks.

momomo
  • 319
  • 1
  • 5
  • 15
  • "... since bcrypt.hash returns another promise ..." your code doesn't use/call `bcrypt.hash` – Thomas Jun 13 '21 at 16:00
  • `return await bcrypt.compare(clientPassword, dbHash);` – Thomas Jun 13 '21 at 16:06
  • You know that a SELECT statement can return more than one column at a time, right? `const dbUsernameObj = pool.query("SELECT varol_users_dealer_username, varol_users_dealer_hash FROM varol_users_dealers_credentials WHERE varol_users_dealer_username = $1", [clientUsername]);` `const dbHashObj = dbUsernameObj;` – Thomas Jun 13 '21 at 16:11
  • @Thomas Thank you for your answer. My code does use/call bcrypt.compare. And unfortunately adding return await on bcrypt.compare doesn't work because the function itself is asynchronous. Is there any possible answer? – momomo Jun 13 '21 at 16:15
  • [`bcrypt.compare()` returns a Promise](https://github.com/kelektiv/node.bcrypt.js#with-promises). Are you using an older version of bcrypt? – Thomas Jun 13 '21 at 16:21

1 Answers1

-1

Try returning a promise

const promise = new Promise((resolve, reject)=>{
        if (dbUsername === clientUsername) {
            bcrypt.compare(clientPassword, dbHash, function(err, result) {
                if (err) {
                    console.log(err)
                }
                resolve(result)
            }); 
        } else {
            resolve(false)
        }
})
return promise

Dharman
  • 30,962
  • 25
  • 85
  • 135
ak100
  • 245
  • 2
  • 3
  • 1
    [What is the explicit promise construction antipattern and how do I avoid it?](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). And [`bcrypt.compare()` returns a Promise](https://github.com/kelektiv/node.bcrypt.js#with-promises) – Thomas Jun 13 '21 at 16:20