Search code examples
node.jsexpressherokupassport-localpassport.js

Passport req.isAuthenticated() always false when deployed to Heroku


I'm using passport with Nodejs. My application works as expected when I run on my localhost. When I deploy to Heroku, however, I find that the req.isAthenticated() function returns false when it should return true even though passport is finding and verifying the user and password. Here is my code which initialises express-session and passport:

app.use(cookieParser());
app.use(session({
  secret: 'foo',
  resave: true,
  saveUninitialized: true,
  cookie: {
    secure: true,
    maxAge: 3600000
    //maxAge: new Date(Date.now() + 3600000)
  }
}));

app.use(flash());
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions

Here is how I define the local passport:

module.exports = function(passport, configIds) {
    passport.use('login', new LocalStrategy({
      usernameField: "email",
      passwordField: "password",
      passReqToCallback: true
    },
        function(req, email, password, cb) {
            //console.log('got email pwd: ' + email + ' ' + password);
        User.getByEmail(email, function(err, user) {
            if (err) { 
                console.log('something went wrong in login strategy getting user: ' + err);
                return cb(err); 
            }
            if (!user) { 
                console.log('problem with user in local strategy');
                return cb(null, false, { message: 'cannot locate user'}); 
            }
            if (!User.comparePassword(user, password)) { 
            console.log('incorrect password for user');
                return cb(null, false, { message: 'incorrect email or password'}); 
            }
          console.log('success: return the user');
            return cb(null, user);
        });
        }
    )),

I'm reaching the success: return the user console output and once again, the req.isAuthenticated() function returns true, as expected, when I run on the localhost. I saw some comments about using https but I'm using secure sockets on both on localhost and Heroku. Here is the middleware I've defined that checks to see if the request is authenticated...

// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {

    // if user is authenticated in the session, carry on 
    if (req.isAuthenticated()) {
        next();
    } else {
        // if they aren't redirect them to the home page
        //return res.redirect('/');
        console.log('User not authenticated. Redirect to home');
        return res.status(401).redirect('/');
    }
}   

edit: I have also checked which cookies are being stored. I can see that when running as localhost a session cookie is being stored but running from Heroku no cookie exists.

Can anyone suggest why this would work, running on localhost but break when running on Heroku?


Solution

  • Okay, this works now and seems to have been because the proxy configuration was not set up properly, as suggested by theprogrammer in one of the comments (thanks!). See the amended code below that fixed the problem...

    app.use(cookieParser());
    app.enable('trust proxy'); // add this line
    app.use(session({
      secret: 'secret',
      resave: true,
      saveUninitialized: true,
      proxy: true, // add this line
      cookie: {
        secure: true,
        maxAge: 3600000,
        store: new MongoStore({ url: config.DB_URL })
      }
    }));
    

    I also added a MongoStore to save the session as suggested by robertklep. Hope this is of help to anyone facing the same problem.