passport icon indicating copy to clipboard operation
passport copied to clipboard

req.user is undefined, passport not working with Express 4.0

Open tschiela opened this issue 11 years ago • 30 comments

I use [email protected] and [email protected].

req.user is alway undefined and so req.isAuthenticated() also not working.

Here is my express-setup:

var env = process.env.NODE_ENV || 'development';

var path = require('path'),
    expressValidator = require('express-validator'),
    config = require('../config/config')[env],
    RedisStore = require('socket.io/lib/stores/redis'),
    redis  = require('socket.io/node_modules/redis'),
    pub    = redis.createClient(),
    sub    = redis.createClient(),
    client = redis.createClient(),
    utils = require('connect').utils,
    cookieParser = require('cookie-parser');
    bodyParser = require('body-parser'),
    expressSession = require('express-session'),
    compress = require('compression'),
    morgan = require('morgan'),
    errorHandler = require('errorhandler'),
    methodOverwrite = require('method-override');

module.exports = function (app, passport, express, io) {
  var RedisSessionStore = require('connect-redis')(expressSession);
  var redisSessionStore = new RedisSessionStore(config.redis.sessions);

  app.use(morgan());
  app.use(cookieParser());
  app.use(methodOverwrite());
  app.use(bodyParser({ keepExtensions: true, uploadDir: config.files.upload.path, limit: config.files.upload.size }));
  app.use(expressValidator());
  app.use(expressSession({
    secret  : 'foo',
    cookie  : {
      expires: false,
      domain: config.cookie.domain
    },
    store: redisSessionStore
  }));

  app.use(passport.initialize());
  app.use(passport.session());

  // response static files
  if(env == 'development'){
    app.use(compress({
      threshhold: 512
    }));
    app.use('/', express.static(path.join(__dirname, '../../frontend')));
    app.use(errorHandler({ dumpExceptions: true, showStack: true }));
  }

  if(env == 'production'){
    app.use(errorHandler());
    app.enable('trust proxy');
  };
}

... and passport-setup:

var LocalStrategy = require('passport-local').Strategy,
    User = require('../model/User');

module.exports = function (passport) {
  // serialize sessions
  passport.serializeUser(function(user, done) {
    var sessionData = {};

    sessionData.user = user._id;

    // store workingAt to build socket.io rooms
    if(user.workingAt){
      sessionData.workingAt = user.workingAt;
    }

    done(null, sessionData);
  });

  // deserialize sessions
  passport.deserializeUser(function(sessionData, done) {
    User.findById(sessionData.user, function (error, user) {
      if(error){
        done(error);
      } else {
        done(null, user);
      }
    })
  });

  // use local strategy
  passport.use(new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password'
      },
      function(email, password, done) {
        User.checkCredentials({email: email, password: password}, function(error, user){
          if(error) {
            return done(error);
          } else {
            return done(null, user);
          }
        });
      }
  ))

EDIT: I try to find the reason of that bug and its seems its related to express-session. On every request i have a new value in req.sessionID, also no cookie will be created with the sessionID.

tschiela avatar May 09 '14 20:05 tschiela

Had isses with express-session. I switched to expressjs/cookie-session and seems to be working fine with [email protected], [email protected], passport-persona

mgutz avatar Jun 12 '14 09:06 mgutz

can u post the post function where u authenticate the user?

Had same issue with custom callback authentication - but not with flash Authentication (flash not works but session will be set with user infos).

naxmefy avatar Jun 13 '14 14:06 naxmefy

There is another issue for this in #222...

vonbirdie avatar Jun 19 '14 13:06 vonbirdie

I had this problem. The fix was to add the express-session secret into the cookie parser. problem solved.

So the fix for above would be:

app.use(cookieParser('foo')); app.use(expressSession({ secret : 'foo', cookie : { expires: false, domain: config.cookie.domain }, store: redisSessionStore }));

notice the cookie parser now contains the session secret.

crsrusl avatar Jun 25 '14 19:06 crsrusl

I had this issue. The problem was really that I was trying to access a redis db number I didn't have access to. When I removed the db from my redis config, it worked again.

trshafer avatar Sep 25 '14 01:09 trshafer

The issue for me was that I was not consistent in linking through my site. Make sure you either prefix ' www.' everywhere or nowhere, or a new session will be started for the two!

bassie1995 avatar Dec 05 '14 11:12 bassie1995

I had the same issue. Turns out it was a dependency issue with express-sesssion. From the Passport site:

If [sessions are] enabled, be sure to use express.session() before passport.session() to ensure that the login session is restored in the correct order.

bicarlsen avatar May 13 '15 06:05 bicarlsen

Putting express.session() before passport.session() fixed the issue for me, thanks.

qdouble avatar Oct 29 '15 18:10 qdouble

+1

Arcrammer avatar May 17 '16 00:05 Arcrammer

+1

shivasurya avatar Nov 26 '16 15:11 shivasurya

If you're using the window.fetch method to send requests to your server, you have to include 'same-origin credentials in your request. See the example below.

fetch(url, { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, credentials: "same-origin" })

valerieernst avatar Jan 23 '17 18:01 valerieernst

Watch out cookie property with 'secure' value if not in under https protocol req.user will be undefined.

SaydChada avatar Mar 15 '17 22:03 SaydChada

Big thanks @valerieernst !

zelenkoff avatar Mar 20 '17 09:03 zelenkoff

@valerieernst HUGE THANK YOU!!!! A ton of Googling and your advice got my stuff working.

justin-haworth avatar Apr 03 '17 19:04 justin-haworth

@valerieernst thanks!

MichaelWStuart avatar Apr 07 '17 07:04 MichaelWStuart

omg @SaydChada thank you so much! I've been stuck for ages, and it was this one line of code driving me insane.

nagmak avatar Apr 10 '17 04:04 nagmak

I did what @mgutz said — Uninstall express-session and use cookie-session instead. It's working for me now so thank you, @mgutz! I believe I had both express-sessionand cookie-session installed so maybe they were conflicting with each other. I'll stick to cookie-session since I know that's working.

Arcrammer avatar Apr 16 '17 14:04 Arcrammer

@valerieernst You are a saint, thank you so much for this small yet absolutely essential piece of information. Here is Github Gold. No wait, but I'll subscribe to your channel. Or follow your feed. +1 your post, whatever, have all the upvotes!

cideM avatar Apr 18 '17 21:04 cideM

In case someone is having this problem due to nginx as ssl proxy to express. Found a working solution here: https://gist.github.com/nikmartin/5902176

andreabat avatar May 26 '17 12:05 andreabat

Guys, since you are using a custom callback to handle success/failures, it becomes the application's responsibility to establish a session . So we need to set req.session.user = {...} in the strategies.

I added a new route to keep using "req.user":

app.use((req, res, next) => {req.user = req.session.user; next()})

webarthur avatar Nov 25 '17 13:11 webarthur

There's a suttle bug with express-session that can bite you, link but cookie-session is basically a drop in replacement that has worked perfectly for me.

nikkwong avatar Nov 30 '17 09:11 nikkwong

It seems to me the real bug here isn't that req.user can be undefined: the real problem is that many different things can all go wrong, and there's no diagnostic info provided to the user whatsoever to help them figure out what they did wrong (which can be especially confusing because "they", the server programmer, may not have done anything wrong, as the problem could be completely client-side).

It seems like at least the majority of the above cases could be caught. For instance, if passport sees two sessions for identical URLs except one has www. and one doesn't, it seems like it would be trivial for it to console.warn("Multiple sessions for the same base URL detected (are you using credentials: 'same-origin'?)").

I would imagine these warnings would be very easy to implement, but they also sound like they'd be hugely valuable. After just losing half a day to the www. one specifically I'd certainly be willing to submit a PR for it, and possibly for others, if desired.

machineghost avatar Feb 13 '18 23:02 machineghost

@machineghost You can always do a PR yourself! 😉

morajabi avatar Feb 22 '18 08:02 morajabi

As I said, I'd be happy to, but I never waste time on PRs that maintainers don't want. Until a project maintainer indicates that such a warning would actually be desired I'll hold off.

machineghost avatar Feb 22 '18 17:02 machineghost

I had same issue, both with req.isAuthenticated() and req.user, here is how I resolved

  • req.isAuthenticated()

resolved by replacing findOne() with find() in findById() method inside deserialize(), then I could save authenticated req, else it was returning nothing.

  • req.user

resolved by adjusting order, first express-session should be stored then passport should be initialized then next session store in passport.session() and after that we can access req.user, after saving session in passport.session()

app.use(session(...))
app.use(passport.initialize());
app.use(passport.session());
// Now we can access req.user so after we will call req.user, if we write it above these, it will always return underfined
app.use(function(req, res, next){
  res.locals.user = req.user || null
  next();
})

asdkazmi avatar Jul 18 '18 09:07 asdkazmi

I have a problem if anybody here could help, please. In my case, cookies are being saved to the browser but they are not being used. I know this because my app doesn't go to a state of logged-in. I just keep getting redirected to google's site every time. I am using passport's google strategy.

EmmyMay avatar Jul 12 '19 21:07 EmmyMay

I had this problem. The fix was to add the express-session secret into the cookie parser. problem solved.

So the fix for above would be:

app.use(cookieParser('foo')); app.use(expressSession({ secret : 'foo', cookie : { expires: false, domain: config.cookie.domain }, store: redisSessionStore }));

notice the cookie parser now contains the session secret.

@crsrusl This worked for me. Before this, I had to manually set req.user = user in my JWT verify callback but after passing the same secret to both cookie-parser and cookie-session, req.user got set automatically. I wonder why this is the case...I would appreciate any explanation regarding this.

Rishabh570 avatar May 29 '20 06:05 Rishabh570

I, too, had this problem, and @SaydChada's hint got me pointed in the right direction:

Watch out cookie property with 'secure' value if not in under https protocol req.user will be undefined.

Also note that if you do indeed want to request a secure cookie be sent to the browser (s/b typical, IMHO), but you're using express-session and terminating TLS somewhere upstream, this little gem right there in the docs is a good answer:

If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express

In my case, I'm running in Google App Engine, configured for TLS/SSL only, which terminates TLS upstream.

See also:

https://github.com/expressjs/session#cookiesecure https://expressjs.com/en/guide/behind-proxies.html https://github.com/expressjs/session/blob/master/index.js#L639

TimJohns avatar Sep 03 '20 10:09 TimJohns

in my case, i use this config, resolveded the problem app.use(session({ secret: "123", resave: true, saveUninitialized: true, cookie: {maxAge: 60 * 60 * 24 * 1000} }));

Wandersonelias avatar Sep 23 '20 17:09 Wandersonelias

app.use(passport.initialize()); app.use(passport.session());

Thank you @asdkazmi !!!

Adding these below the express session use in app.js did the trick for me here in March 2024 :-)

locohost avatar Mar 24 '24 17:03 locohost