#1020·passport

Using AuthenticationCallback/req.logIn() breaks deserialization in 0.7.0

Author: Mark-Elliott5Created Mar 10, 2024Updated Jun 13, 2025

I am creating a chat app with websockets and want to use req.user within websocket event listener handlers. Using a simple passport.authenticate('local') works fine and populates req.user in later requests as expected. However, I want to provide an AuthenticationCallback to send a variable JSON message back to my React frontend on login success/failure rather than just a 401 status. User information is retrieved successfully but later requests do not deserialize. Downgrading to 0.5.3 fixes the issue.

Expected behavior

req.user is populated through deserialization on requests after authorization

Actual behavior

req.user is undefined on requests after authorization

Steps to reproduce

Route:

javascript
app.post('/login', (req: IReq, res: IRes, next: INext) =>
  passport.authenticate('local', function (err, user) {
    if (err) {
      console.log('err');
      return res.json({
        authenticated: false,
        message: 'Server error. Try again.',
      });
    }
    if (!user) {
      return res.json({
        authenticated: false,
        message: 'User not found.',
      });
    }
    req.logIn(user, { session: true }, (err) => {
      console.log(err);
    });
    res.json({ authenticated: true });
  } as AuthenticateCallback)(req, res, next)
);

My passport configuration:

javascript
import { Application } from 'express';
import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import 'dotenv/config';
import session from 'express-session';
import bcrypt from 'bcrypt';
import { User } from '../types/mongoose/User';

const configureAuthentication = (app: Application) => {
  const secret = process.env.SECRET;
  if (secret === undefined)
    throw new Error('.env secret key not found! Sessions need a secret key.');

  app.use(
    session({
      secret,
      resave: false,
      saveUninitialized: true,
    })
  );

  passport.use(
    new LocalStrategy(async (username, password, done) => {
      try {
        const user = await User.findOne({ username });
        if (!user) {
          return done(null, false);
        }
        const match = await bcrypt.compare(password, user.password);
        if (!match) {
          return done(null, false);
        }
        return done(null, user);
      } catch (err) {
        return done(err);
      }
    })
  );

  passport.serializeUser((user, done) => {
    done(null, user._id);
  });

  passport.deserializeUser(async (_id, done) => {
    try {
      const user = await User.findById(_id);
      done(null, user);
    } catch (err) {
      done(err);
    }
  });

  app.use(passport.initialize());
  app.use(passport.session());
};

export default configureAuthentication;

My websocket (logs undefined on 0.7.0, logs correctly on 0.5.3):

javascript
import WebSocket from 'ws';
import { IReq } from '../types/express';

function websocketHandler(ws: WebSocket, req: IReq) {
  ws.on('message', function (msg: WebSocket.RawData) {
    console.log(req.user); // undefined
    ws.send(msg);
  });
}

Environment

  • Operating System: macOS 14.1.1
  • Node version: 20.10
  • passport version: 0.7.0