Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

passport messing up req.session? #77

Closed
saiko-chriskun opened this Issue · 20 comments

4 participants

@jaredhanson
Owner

What host are you accessing the site from? Your Twitter callback is using http://127.0.0.1:3000/auth/twitter/callback, so if you are using a different host (such as localhost), the session will not be consistent.

@saiko-chriskun

My hosts are consistent, I'm using 127.0.0.1, and also req.session should just be parsing the connect.sess cookie, right? And that has all the right info in it.

@saiko-chriskun

req.cookies:

{ 'connect.sess': 's:j:{"passport":{},"oauth:twitter":{"oauth_token":"2I5pfXGseNp3jz8GrIfRi5nfQRYq6B1x4pnccHlBuw0","oauth_token_secret":"yQdGqJhA3SedExgYUgWuWQkOlrXhihwaf6jhWkyG3YQ"}}.+fxYbysR15HErVFRSCWGjL22Dnu+ALcZQbYcTc0Opo8' }

req.session

{ passport: { user: '1' } }

@saiko-chriskun

are you not seeing this behavior at all?

@saiko-chriskun

so for now I'm just adding a middleware to manually parse out req.cookies =/

@saiko-chriskun

any word...?

@jaredhanson
Owner

@saiko-chriskun I'm investigating this now. I'm not reproducing with the latest versions of Express and Connect. Are you still experiencing this?

@smithwinston

I have the same issue, I followed the passport/expressjs-3.x example, I'm using passport ~0.1.15 with passport-local ~0.1.6 and expressjs 3.1.x. I set up with:

  app.use express.cookieParser()
  app.use express.session({ secret: "keyboard cat" })
  app.use passport.initialize()
  app.use passport.session()

When I login successfully, from my logging I can see it calling my serializeUser callback with the user object. However, req.isAuthenticated() then returns false and I end up back at the login page (note I never see my deserializeUser callback being called by passport when I try to load a view).

@jaredhanson
Owner

What are you using for your session store? It looks like the built-in MemoryStore, which won't maintain sessions in any clustered deployment.

@jaredhanson
Owner

Curious because this bug report is specifically about about using the cookieSession store, and based on your configuration, that doesn't appear to be what you are using.

@smithwinston

I'm not specifying any store, so you are right, I'm using the memory store. This is just a dev environment, I have no cluster running. I think I misunderstood the cookieParser() directive! I still have the issue of isAuthenticated() returning false though ...

@jaredhanson
Owner

Make sure you're not switching between different hostnames (like localhost and 127.0.0.1) while navigating the app.

Apart from that, it'd help if you can dump the contents of the session for each request to debug what is happening. I do something like:

app.use(function(req, res, next) {
    console.log('-- session --');
    console.dir(req.session);
    console.log('-------------');
    console.log('-- cookies --');
    console.dir(req.cookies);
    console.log('-------------');
    console.log('-- signed cookies --');
    console.dir(req.signedCookies);
    console.log('-------------');
    next()
  });
@smithwinston

Interesting, aside from the first run, the dump always looks like this:

-- session --
{ cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true },
  passport: {},
  flash: {} }
-------------
-- cookies --
{ 'connect.sid': 's:WE1CY9tQ/dDA82s/62d5YFt.Y2yTuzjC9UZ7MQIhFu834wAwWFvXt7iTIsZl4eVH3Eg' }
-------------
-- signed cookies --
{}
-------------

I am using a Chrome incognito window so it doesn't keep any state, the first time through, when I go to /home there is nothing in the cookies (i.e. no connect.sid). At that point, it redirects to /login and the dump is as above. Even after I post to /login and then redirect to /home, the dump is like this. The passport hash is always empty.

@jaredhanson
Owner

Have you disabled sessions? What's your login route and verify callback look like?

Also, I would dump the session again after login (before any redirects), to verify that the passport hash is set correctly then.

@smithwinston

It's basically right out of your passport/expressjs-3.0 sample; run through js2coffee:

  # Configure passport
  passport.use new LocalStrategy((username, password, done) ->
    # Look up this user
    User.get username, (err, userobj) ->
      if err
        return done(err)
      unless userobj
        return done(null, false,
          flash:
            error: "Invalid username or password"
        )
      unless userobj.validPassword(password)
        return done(null, false,
          flash:
            error: "Invalid username or password"
        )
      console.log "Success ... user is logged in: #{JSON.stringify(userobj)}"
      done null, userobj
  )

  passport.ensureAuthenticated = (req, res, next) ->
    console.log "ensureAuthenticated: isAuthenticated=#{req.isAuthenticated()}"
    if req.isAuthenticated()
      return next()
    req.flash('info', 'Please log in to the application.')
    req.session.initialURL = req.url
    res.redirect "/login"

  passport.serializeUser (user, done) ->
    console.log "Serializing user: #{JSON.stringify(user)}"
    done null, user.getId

  passport.deserializeUser (id, done) ->
    console.log "Deserializing user: #{id}"
    User.get id, (err, user) ->
      console.log "Got: #{JSON.stringify(user)}"
      done err, user

  app.get '/login', (req, res) ->
    res.render "#{__dirname}/views/login",
      user: req.user
      title: 'Login'

  app.post "/login", (req, res, next) ->
    passport.authenticate("local", (err, user, info) ->
      return next(err) if err
      unless user
        for type,msg of info.flash
          req.flash(type, msg)
        return res.redirect("/login")
      req.logIn user, (err) ->
        if err
          return next(err)

        # !!!! HERE !!!!
        initialURL = req.session.initialURL ? app.settings.defaultURL
        req.session.initialURL = undefined
        res.redirect initialURL
    ) req, res, next

  app.get "/logout", (req, res) ->
    req.logout()

I added some additional tracing and after calling passport.authenticate, then calling req.logIn in the callback, in the success part of the logIn callback (I added a 'HERE' comment in the code above), I see this:

passport: { user: [Function] },

But this is gone after the redirect:

passport: {},

I haven't disabled sessions (that I'm aware of ...).

@jaredhanson
Owner

This is your problem:

passport: { user: [Function] }

Functions won't be serialized cleanly to JSON, which is why it is disappearing from the session. Make sure your user.getId function is correctly returning a number or a string.

@jaredhanson
Owner

I'm not sure the CoffeScript syntax, but you probably need to invoke the getId function

done null, user.getId() // <-- note the parens to invoke the function
@smithwinston

That was my issue! a missing set of parens. Thank you for your help!

@jparchure

I have a similar problem, but with facebook

Here's my code

var passport = require('passport'),
 FacebookStrategy = require('passport-facebook').Strategy;

 function findById(id, fn) {
   User.findOne(id).exec(function (err, user) {
     if (err) {
       return fn(null, null);
     } else {
       return fn(null, user);
     }
   });
 }

 function findByFacebookId(id, fn) {

   User.findOne({
     facebookId: id
   }).exec(function (err, user) {
     if (err) {   
       return fn(null, false);
     } else {
       return fn(null, user);
     }
   });
 }

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

 passport.deserializeUser(function (id, done) {
   findById(id, function (err, user) { 
     done(err, user);
   });
 });

 passport.use(new FacebookStrategy({
     clientID: "ID",
     clientSecret: "Secret",
     callbackURL: "http://localhost:1337/user/facebook/callback", //Same as the one on Facebook app
     enableProof: false
   }, function (req,accessToken, refreshToken, profile, done) {

     findByFacebookId(profile.id, function (err, user) {
  // Create a new User if it doesn't exist yet
       if (!user) {

         User.create({
           facebookId: profile.id
         }).exec(function (err, user) {
                if (user) {
             return done(null, user, {
               message: 'Logged In Successfully'
             });
           } else {
             return done(err, null, {
               message: 'There was an error logging you in with Facebook'
             });
           }
         });
  // If there is already a user, return it
       } else {
         req.session.fbAccessToken = accessToken; 
 //THIS IS NOT BEING SET, saying that TypeError: Cannot set property 'fbAccessToken' of undefined
         return done(null, user, {
           message: 'Logged In Successfully'
         });
       }
     });
   }     
 ));

This is my middleware

var passport = require('passport');
var express = require('express');
var session= require('express-session');
var cookieParser = require('cookie-parser');
var cookieSession = require('cookie-session');
var app=express();

   module.exports.express = {
    customMiddleware: function(app){
        sessionStore = new session.MemoryStore;
        app.use(cookieParser('foo'));
    app.use(session({
      secret : 'foo',
     store: sessionStore
    }));
       / Passport
    app.use(passport.initialize());
    app.use(passport.session());
   app.use(function(req, res, next){
        res.locals.user = req.session.user;
        next();
    });
  }};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.