Search code examples
mysqlnode.jsexpresspassport.js

Express.js using await with passport


I'm trying to add mySQL to passport.js to authenticate users in express.js, but can't seem to get await working. Server.js:

initializePassport(
  passport,
  function(email) {
    pool.getConnection(function(err, connection) {
      if (err) throw err;
      console.log("Connected!");
      pool.query("SELECT * FROM users WHERE email = ?", email, function (err, result) {
        if (err) throw err;
        return result[0];

        connection.release();
      });
    });
  },
)

The passport config

function initialize(passport, getUserByEmail) {
  const authenticateUser = async (email, password, done) => {
    try {
      const user = await getUserByEmail(email);
      console.log(user)
    } catch (e) {
      return done(e)
    }

Right now it just prints undefined for user, and then prints Connected. I'm not sure why the await user isn't working.


Solution

  • Well if that's getUserByEmail(), then it doesn't return a promise that is connected to when it's asynchronous operations are done, therefore, doing await getUserByEmail() doesn't wait for anything.

    await ONLY does something useful if you are awaiting a promise that is connected to the operation you want to await for. Since you aren't even awaiting a promise, that await does nothing useful. You would need to change getUserByEmail() so that it returns a promise that is connected to the asynchronous operation you're trying to wait for.

    For a function to return a promise that is connected to the asynchronous operations, you need to use promise-based asynchronous operations, not plain callback asynchronous operations, everywhere in that function. These are all database operations and all modern databases have a promise-based interface now so what you really want to do is to switch .getConnection(), .query() and .release() to all use promise-based operations. This will also make it a lot simpler to implement proper error handling and proper communication back to the caller of errors.

    I don't know mysql particularly well myself, but here's a general idea. The promise interface comes from the module mysql2/promise:

    const mysql = require('mysql2/promise');
    const pool = mysql.createPool({...});
    
    initializePassport(passport, async function(email) {
        let connection;
        try {
            connection = await pool.getConnection();
            console.log("Connected!");
            let result = await pool.query("SELECT * FROM users WHERE email = ?", email);
            return result[0];
        } catch(e) {
            // log the error and the rethrow so the caller gets it
            console.log(e);
            throw e;
        } finally {
            if (connection) {
                connection.release();
            }
        }
    });