node.jsexpresspassport.jsexpress-sessionpassport-local

passport.serializeUser & passport.deserializeUser not working


I try to do a login via a LocalStrategy in Passport, but the serializeUser and deserializeUser functions don't seem to be called at all. The versions of the ‘Relevant’ packages are:

"express": "^4.21.2",
"express-mysql-session": "^3.0.3",
"express-session": "^1.18.1",
"passport": "^0.7.0",
"passport-local": "^1.0.0",

passport.js file: Console Outputs are only ‘login’, never ‘serialize’ or ‘deserialize’.

const passport = require("passport"),
    LocalStrategy = require("passport-local").Strategy;

passport.use("local.login", new LocalStrategy({
    usernameField: 'address',
    passwordField: 'token',
    passReqToCallback: true
}, async (req, _username, _password, done) => {
    const body = JSON.parse(req.body.body);

        const user = {
            id: `${Date.now()}`,
            token: "123"
        };

        console.log("login");
        return done(null, user);
}));

passport.serializeUser((user, done) => {
    console.log("serialize");
    return done(null, user.id);
});

passport.deserializeUser((id, done) => {
    console.log("deserialize");
    return done(null, {
            id: id,
            token: "123"
});

The rest of the code in this respect

index.js

const express = require("express"),
    passport = require("passport"),
    session = require("express-session"),
    MySQLStore = require("express-mysql-session")(session),
    { database } = require("./lib/config/keys"),
    bodyParser = require("body-parser"),
    { body } = require("express-validator");

...

app.set("port", process.env.PORT || 80);

...

// Middlewares
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(session({
    secret: "secret",
    resave: false,
    saveUninitialized: true,
    store: new MySQLStore(database)
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(body());
require("./passport");

app.use((req, res, next) => {
    app.locals.user = req.user;
    next();
});

...

auth.js

// Requirements
const express = require("express"),
    router = express.Router(),
    passport = require("passport");

router.post("/login", async (req, res, next) => {

    . . .

    passport.authenticate("local.login", (err, user, info, status) => {
        if (err) {
            console.error(err);
            return res.send(false);
        }
        res.send(true);
    })(req, res, next);

}
);

. . .

Solution

  • The problem was that req.login(user, callback) was missing inside the authentication callback. Passport doesn’t automatically serialize the user unless req.login() (or req.logIn()) is called. This means that the serializeUser and deserializeUser functions were never triggered.

    Solution: Modify the /login route in auth.js to include req.login() after successful authentication:

    router.post("/login", async (req, res, next) => {
        passport.authenticate("local.login", (err, user, info) => {
            if (err) {
                console.error(err);
                return res.send(false);
            }
    
            if (!user) {
                return res.send(false);
            }
    
            // Here.
            req.login(user, (loginErr) => {
                if (loginErr) {
                    console.error(loginErr);
                    return res.send(false);
                }
                res.send(true);
            });
        })(req, res, next);
    });
    

    Why this works:

    After adding req.login(user, callback), everything works as expected! Now, serializeUser and deserializeUser are being called properly. Hopefully, this helps anyone else facing the same issue.