Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express.js / Passport.js: Where is req.user stored?

I am developing a web application that is going to be deployed to Heroku.

I have chosen to go with a Node.js stack as I am fed up with "traditional" web frameworks. I am designing the app on Express.js. I've found it very productive and intuitive compared to e.g. Django or Grails.

So the web app is going to have features for both guests and authenticated users. And as the app is deployed to Heroku, which is a cloud platform service, the application cannot have any internal state stored inside the server because of Heroku's load balancers and practices in general. And the fact is that having internal state is also bad design in a distributed environment.

My local development setup has a Redis instance (for storing sessions) and a MongoDB instance (for storing user data, e.g. Facebook user details). I am using Passport.js and passport-facebook to handle authentications. Currently, I have only Facebook authentication implemented which works fine at least locally.

The problem is that I am not sure nor have I read anywhere about how Express / Passport magically populates the req.user object. I'm a bit suspicious about that and it feels like that is stored in server's memory.

passport.serializeUser(function(user, done) {
    console.log(
        "This outputs a complete" +
        "User Profile object when the user logs in.", 
        user);
    done(null, user);
});

passport.deserializeUser(function(obj, done) {
    console.log(
        "And this too, but I'm afraid that" +
        "obj comes from memory.", 
        obj);
    done(null, obj);
});

Passport.js documentation does not tell very well about this one. My guess is that serializeUser() gets the user from Facebook, but deserializeUser() takes it from memory?

If so, would it be a solution to dump the raw user data into the Mongo database in serializeUser() and then get it from there in deserializeUser()?

like image 750
tukkaj Avatar asked Nov 25 '13 20:11

tukkaj


1 Answers

req.user is a convenience property that is an alias for req.session.user, which is stored in redis. So for session-enabled requests, the session data is loaded from redis, then req.user is set to be the same as req.session.user for convenience, then your code runs and responds to the request, and the in-memory versions of these are eligible for garbage collection once the response is sent. The copies in redis survive until the session expires.

If so, would it be a solution to dump the raw user data into the Mongo database in serializeUser() and then get it from there in deserializeUser()?

Yes, that's the general pattern if you want to use the user data as part of your application data (which is typical). So in the end mongo will have every user who has ever logged in, and redis will have every user with a currently-active session, and memory will have every user the app is in the middle of handling a request from at this instant.

like image 60
Peter Lyons Avatar answered Sep 23 '22 15:09

Peter Lyons