I am using passport.js for Google, Facebook and Twitter logins only.

Node.js v0.8.19 with express.js 3.1.0, and passportjs version 0.1.16. (passport-facebook - 0.1.5, twitter - 0.1.4 passport-goolge-oauth - 0.1.5 )

Everything works fine for a while, after an hour or so of the app running passport.js stops serializing the user into the req.user session.

Facebook and google are receiving meaning full data from their respective api's

passport.use(new FacebookStrategy({
    clientID: FACEBOOK_APP_ID,
    clientSecret: FACEBOOK_APP_SECRET,
    callbackURL: "http://localhost:3000/auth/facebook/callback"
  },
  function(accessToken, refreshToken, profile, done) {
      var temp = {} 
      temp.name = profile.displayName
      temp.id = profile.id
      console.log(temp)
      return done(null, temp);
}));

The console.log here will successfully print user id and name, however after calling

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

passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

Serialize and deserialize are taken from the passport-facebook example.

The user will not be attached to req.user.

Twitter never gets that far, after returning to the callback url, twitter gives the error:

Error: failed to find request token in session
[03/11 23:28:24 GMT]     at Strategy.OAuthStrategy.authenticate            

Note: these failures only happen after a period of time, the work properly for a while. Thats why I think it may be a memory issue, like Im saving the session in memory instead of a cooke.

This is my express app configuration

app.configure(function(){
  app.set('port', process.env.PORT || 8080);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieSession({ secret: 'tobo!', cookie: { maxAge: new Date(Date.now() +     3600000), }}));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

I have looked at the mailing list etc, but I could not find something matching this problem. I have checked on my localhost and on a nodejitsu server. Everything works for a while then fails.

share|improve this question
3  
Neither passport.serializeUser() or deserializeUser() look like they could ever work. serializeUser() is supposed to take an object and serialize it into a string that can be used in a cookie to uniquely identify a user. That is usually done by calling done(null, user.id). deserializeUser is supposed to take the same id (from a cookie) and find the correct set of data in a database. With mongodb you could do User.findById(id, function(err, user) { done(err, user); }); – Andreas Hultgren Mar 12 '13 at 9:03
    
So they must be strings? – Eoin Murray Mar 12 '13 at 9:46
    
Here in the passport-facebook example they have the same serialize and deserialize as I do. – Eoin Murray Mar 12 '13 at 9:49
    
Hm... now I'm not sure. I haven't used the facebook strategy in particular, but i assume it should always work the same. In passport's own docs serializeUser returns a string (which is what the name implies), so iäd place my bet on that it's the docs for passport-facebook that is wrong. If you don't return something else than what was sent to serializeUser, those methods doesn't actually do anything. – Andreas Hultgren Mar 12 '13 at 10:03
1  
@JohnEcho you're using maxAge as if it was expires, which might be the problem. maxAge should be passed the number of milliseconds after which the session expires (whereas expires takes a timestamp, as in your code) – robertklep Mar 12 '13 at 11:05

First you must understand what serialize and deserialize are meant for.

1) serializeUser take a user object and store any information you want in the session, when you return done(null, user), as per your first question.

2) deserializeUser take the information stored in the session (sent by cookieSession in every request) and checks if the session is still valid for a user, and if(!err) done(null,user) is true, keeps the user in the session, where else done(err,null) removes it from the session, redirecting you to whatever your app.get('/auth/:provider/callback') sends the user to after checking if the session is timed out or not. This should clarify things for your second question.

share|improve this answer

I still do not understand why the problem came about but I have solved it by doing the following.

Changing

  app.use(express.cookieSession({ secret: 'tobo!', cookie: { maxAge: new Date(Date.now() +     3600000), }}));

to

app.use(express.cookieSession({ secret: 'tobo!', maxAge: 360*5 }));

I think that serializing the entire user object should work since deserializeUser will just pass back the passed cookie. But by not serializing the entire user object it is working.

passport.serializeUser(function(user, done) {
    console.log('serializeUser: ' + user._id)
    done(null, user._id);
});

passport.deserializeUser(function(id, done) {
    db.users.findById(id, function(err, user){
        console.log(user)
        if(!err) done(null, user);
        else done(err, null)  
    })
});

I have had zero issues since I did this.

share|improve this answer
1  
Not sure if this is actually the issue, but I think maxAge on the cookie is supposed to be the number of seconds the cookie is supposed to last, not the actual time that it should expire (which is what you put there). – Will Sep 20 '13 at 2:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.