Application crash during deserializeUser when user record is missing
0 reputation · 02 Aug 2021, 20:47 UTC
0 reputation · 02 Aug 2021, 20:47 UTC
Passport.js utilizes the deserializeUser function to retrieve a user object from a data store based on the ID stored in the session. In a production environment using passport-local, a race condition occurs when a user record is deleted from the database while an active session cookie persists in the client's browser.
If the data access layer returns null or undefined for a non-existent user, the middleware may fail to handle the empty response gracefully, potentially leading to unhandled exceptions or application crashes during the request lifecycle.
deserializeUser to prevent process crashes?34775 reputation · 02 Aug 2021, 21:00 UTC
When the database lookup in deserializeUser returns null or undefined, the callback must be invoked with a null user, not an error. Passport will then treat the request as unauthenticated and skip protected routes.
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
if (err) return done(err); // real DB error
if (!user) return done(null, null); // user was deleted
return done(null, user);
});
});
Key points:
!user before accessing properties.done(null, null) for a missing record – this signals Passport that the session is no longer valid.err for genuine failures.After done(null, null) Passport sets req.user to undefined. Any middleware that expects a user should guard against that state, e.g.:
app.get('/profile', function(req, res, next) {
if (!req.user) return res.status(401).send('Not authenticated');
// safe to use req.user
});
Passport itself does not automatically destroy the session when deserialization fails. The done(null, null) callback simply signals that the current session is not associated with a valid user. If you want to remove the session cookie immediately, call req.logout() or req.session.destroy() inside a custom middleware after deserialization.
If you see a stack trace that shows a property access on undefined inside your own code, double‑check that you are not dereferencing req.user without a guard. If the crash occurs before the deserializeUser callback returns, it likely means you omitted the null check.
Use comments to ask for clarification. Post a solution as an answer.
5,550 reputation · 03 Aug 2021, 06:03 UTC
While calling done(null, null) prevents an immediate crash, it is important to distinguish between a missing record and a failed authentication state. In many Passport.js implementations, passing false as the second argument—done(null, false)—is the explicit way to signal that the user is no longer authenticated.
This distinction is critical for downstream middleware. If the callback returns null, some custom guards may still perceive the session as "active" but empty, whereas false explicitly tells Passport the authentication attempt failed. To verify this behavior in your environment:
null for a specific ID.deserializeUser invokes the callback with (null, false).req.user is undefined and that your route guards trigger a 401 or redirect rather than a TypeError.