req.session.passport and req.user blank , and req.isAuthenticated returns false after initial successful login using passport-facebook

Karthic Rao picture Karthic Rao · Jul 22, 2014 · Viewed 7.9k times · Source

After the initial successful login from Facebook and login redirection callback using passport-facebook 1.0.3 and express 4.6.1,req.session.passport and req.user contains the value set during the serialize call(which i get from the stragegy) , but on subsequent visits to different routes on the site the req.session.passport and req.user is blank , and req.isAuthenticated() returns false , so after the initial successful login from FB the ensureAuthentication method on all other routes fails . I'm not using a cluster setup , so i believe the memory store is enough to handle this , the express configuration looks fine(i mean the order) , here is my express configuration

configExpressApp.set('views',  './views');
configExpressApp.set('view engine', 'jade');
configExpressApp.use(morgan('dev'));
configExpressApp.use(cookieParser());
configExpressApp.use(bodyParser.urlencoded({
  extended: true,
}));
configExpressApp.use(bodyParser.json());
configExpressApp.use(expressSession({
  secret:'MyExpressSecret', 
  saveUninitialized: true,
  resave: true
}));
configExpressApp.use(passport.initialize());
configExpressApp.use(passport.session());
configExpressApp.use(methodOverride());
configExpressApp.use(express.static('./public'));   

Here is the req.session object on the initial successfull login and redirection ,The req.user contains the same data as the req.session.passport.user

{ cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true },
  passport: 
   { user: 
      { _id: 53ce23e3121421f229a438f8,
        info: false,
        loginType: 'fb',
        fbId: 'MyId',
        name: 'Karthic Rao',
        email: '[email protected]'

        }
     }
} 

this is the information i associated earlier with the done() callback inside the strategy and also inside the serialization call . After the successfull login and callback, i use res.redirect to redirect the user to a different route , but the requests coming from that route contains the sessionID (so i dont think its the issue with the session store), but the req.user field doesnt exist(may be because passport.initialize() and passport.session() middlewares dont find the request to be authenticated) and the req.session.passport field is empty , here are the details from the console.log of the req object .

sessionID: 'I9R1c3PIYgDW5OpWbNT7qb02Hn4lOeAB',
session: 
   { cookie: 
      { path: '/',
        _expires: null,
        originalMaxAge: null,
        httpOnly: true },
     passport: {} },

Here is my deserialize method

passport.deserializeUser(function(user, done) {
    console.log('deserialize loginType facebook');
    db.collection("users").findOne({
        fbId: user.id
    }, function(err, docs) {
        console.log(docs);
        done(err, docs);
    });
});

Here is my serialize method

passport.serializeUser(function (user, done) { 
    console.log(user);
    done(null, user);
});

This is creating a great hindrance to my development , how can i sort this out ??

Answer

Waldo Jeffers picture Waldo Jeffers · Jul 29, 2014

Well, if you could add the code where you use your strategy (it should be in the middleware), that would give us a complete view of the problem, because we need to know what object is sent to serializeUser.

(Very) basically, when a user tries to authenticate, things happen that way :

  • Passport tries to authenticate your user against Facebook servers
  • If it succeeds, the callback function (or successRedirect) is called with an object containing the user's details
  • Then, Passport makes a call to req.login to store some info about the user in session
  • Then serializeUser is called and effectively store the data you specified in session.

BUT from the code you posted, I suspect that in your deserializeUser, user.id is undefined, because the user object that is stored in session uses an ID field called _id and not id.

If you change

 db.collection("users").findOne({
        fbId: user.id

to

db.collection("users").findOne({
        fbId: user._id

db.collection("users").findById(user._id, [fields],[options],[callback]);

I think it should work.

EDIT : I edited my answer based on @BrandonZacharie's remark, which pointed out an error in my code.