jaredhanson / passport

Simple, unobtrusive authentication for Node.js.
https://www.passportjs.org?utm_source=github&utm_medium=referral&utm_campaign=passport&utm_content=about
MIT License
22.85k stars 1.24k forks source link

passport is empty in session but has user in sessionStore #452

Open bogas04 opened 8 years ago

bogas04 commented 8 years ago

I've spent 4 hours scrolling through all SO posts about req.isAuthenticated() giving false always and then realizing that my session.passport lacks user itself and then figuring out that it appears in sessionStore once (I am using MemoryStore for now) and on second request it disappears, god knows why.

Please help me out.

import express from 'express';
import passport from 'passport';
import bodyParser from 'body-parser';
import constants from '../constants';
const app = express();

app.use('/', express.static(__dirname + '/../client'));

// Config
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json({ limit: '25mb' }));
app.use(require('express-session')({ 
  secret: 'yolo 123',
  resave: true,
  saveUninitialized: false,
  cookie: { maxAge : 24*60*60*1000 }, 
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(require('./passport-local'));

app.get('/test', (req, res) => { 
  console.log(req.sessionStore, req.sessionID, req.session);
  res.status(200).end(req.isAuthenticated() ? 'logged in': 'logged out');
});

app.post('/login', passport.authenticate('local'), (req, res) => {
  let user = req.user.toJSON();
  delete user.password;
  res.status(200).json({ user })
});
...

./passport-local.js

import { Strategy } from 'passport-local';
import constants from '../constants';
import passport from 'passport';
import { User } from './db';

passport.serializeUser((user, done) => done(null, user.id));

passport.deserializeUser((user, done) => (
  User.where({ id: user.id })
  .fetch()
  .then(u => done(null, u))
));

module.exports = new Strategy({ usernameField: 'username', passwordField: 'password' }, (username, password, done) => (
  User.where({ username }).fetch()
  .then(user => {
    if(user) {
      if (!password.compare(password, user.toJSON().password)) {
        return done(null, false, { message: 'Incorrect password.' });
      } else {
        return done(null, user);
      }
    } else {
      return done(null, false, { message: 'Incorrect username.' });
    }
  })
  .catch(console.log)

Flow: Login -> I receive user object with correct details from DB -> I visit /test

GET /test
MemoryStore {
  sessions: { N6YkV5_LIZRBTDcXDPMhgNSRRxtbZDIX: '{"cookie":{"originalMaxAge":86400000,"expires":"2016-01-09T12:09:21.366Z","httpOnly":true,"path":"/"},"passport":{"user":"2"}}' },
  generate: [Function],
  _events: { disconnect: [Function], connect: [Function] },
  _eventsCount: 2 } 'N6YkV5_LIZRBTDcXDPMhgNSRRxtbZDIX' Session {
  cookie: 
   { path: '/',
     _expires: Sat Jan 09 2016 17:39:21 GMT+0530 (IST),
     originalMaxAge: 86400000,
     httpOnly: true },
  passport: {} }

I revisit /test

GET /test
MemoryStore {
  sessions: { N6YkV5_LIZRBTDcXDPMhgNSRRxtbZDIX: '{"cookie":{"originalMaxAge":86400000,"expires":"2016-01-09T12:09:24.179Z","httpOnly":true,"path":"/"},"passport":{}}' },
  generate: [Function],
  _events: { disconnect: [Function], connect: [Function] },
  _eventsCount: 2 } 'N6YkV5_LIZRBTDcXDPMhgNSRRxtbZDIX' Session {
  cookie: 
   { path: '/',
     _expires: Sat Jan 09 2016 17:39:24 GMT+0530 (IST),
     originalMaxAge: 86400000,
     httpOnly: true },
  passport: {} }

EDIT: Just used database (postgres) for session store, exact same behaviour. What piece of code is making an update entry on the passport: {} in session store and thus emptying it?

EDIT2: I'm adding/removing user to/from session myself in my login and logout routes for now, and they are persistent. I guess this has to do with passport getting confused or something like that.

MattMcFarland commented 8 years ago

I am having the exact same problem. Instead of using a /test endpoint, I just create a all-route endpoint that logs out the session info no matter what:

  app.use((req, res, next) => {
    var status = req.isAuthenticated() ? 'logged in' : 'logged out';
    console.log(
      'status:', status, '\n',
      req.sessionStore,
      req.sessionID,
      req.session
    );
    next();
  });

So when I am not logged in:

status: logged out 
 MemoryStore {
  sessions: {},
  generate: [Function],
  _events: { disconnect: [Function], connect: [Function] },
  _eventsCount: 2 } i41u4l-rapAOtbT-loUfTFR4K8Tpxw5m Session {
  cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true } }

Then after I login:

status: logged out 
 MemoryStore {
  sessions: {},
  generate: [Function],
  _events: { disconnect: [Function], connect: [Function] },
  _eventsCount: 2 } B_P8564UmyyTJnQgCyJ9z_IaOWVcgHZ7 Session {
  cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true } }

I setup like this:

/*  Server I/O  ---------------------------------------------------------- */
{

  // i/o middlewares
  app.use(cookieParser());
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({extended: false}));
  app.use(session({
    secret: 'K7@*{GwHdq1@+ChhB%|M|r$1JkW|15ip^Kwguq#^ETD',
    name: '_codepix',
    resave: false,
    saveUninitialized: false
  }));

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

/* Router setup */
{
  app.use((req, res, next) => {
    var status = req.isAuthenticated() ? 'logged in' : 'logged out';
    console.log(
      'status:', status, '\n',
      req.sessionStore,
      req.sessionID,
      req.session
    );
    next();
  });

  // Static paths
  app.use(express.static(staticpath));
  app.use('/c0dez/data', express.static('data'));

  // api endpoint
  app.use('/api', (req, res, next) => {
    if (app.get('rasterizer')) {
      req.rasterizer = app.get('rasterizer');
    }
    next();
  });
  app.use('/api', api);

  // root endpoint
  app.use('/', root);

}

What gives ??

bogas04 commented 8 years ago

Is it because of ES6 syntax? @MattMcFarland I think I've found the issue, I wasn't using CORS.

Server Side:

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

Client Side:

fetch('endpoint.json', {
  credentials: 'include',
...
bogas04 commented 8 years ago

NOTE : Passport is still not filling req.user, I am manually adding user to session at login and removing on logout, so I guess the issue is still valid.

AdamZikmund commented 8 years ago

Same problem here :(

brianmmorton commented 8 years ago

Same problem here as well

sethisidd commented 8 years ago

Same problem here as well

jdposthuma commented 8 years ago

Me too. I feel like this is due to a race condition in the express session store, but I'm not sure. Very frustrating. Does anyone have even a dirty workaround?

AdamZikmund commented 8 years ago

I used JWT instead of sessions :) and it's better solution.

rhinodavid commented 7 years ago

+1 one on this. Same issue. When I make the same requests with postman everything works fine. I've tried adding CORS support and made sure the cookie is in fact coming across.

jdposthuma commented 7 years ago

I've fixed this, but it hasn't been accepted as the Travis CI is failing for some reason:

https://github.com/jaredhanson/passport/pull/504

abelosorio commented 6 years ago

Any progress on this issue? It's frustrating.

MuhammadHasham23 commented 6 years ago

Any workaround, i have accessed that from sessionStore manually, but that appears to be redundant approach though.

JorgeJoseAbad commented 5 years ago

Old issue, 2016, but it hit me now... in Auth-controller I have:

const express         = require("express");
const authController  = express.Router();
const passport        = require("passport");

// Our user model
const User            = require("../api/user/user.model");
const upload          = require('../config/multer');

const isAuthenticated = require('../config/isAuthenticated'); //prueba

// Bcrypt let us encrypt passwords
const bcrypt         = require('bcrypt');
const bcryptSalt     = 10;

The login is:

authController.post("/login", function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    console.log("intentamos hacer login");
    console.log(err);
    if (err) {
      res.status(500).json({ message: 'Something went wrong in passport.authenticate' });
      return;
     }

    if (!user) { return res.status(401).json(info); }

    req.login(user, function(err) {
      if (err) {
        console.log ("dentro del reglogin");
        return res.status(500).json({
          message: 'something went wrong :('
        });
      } else{
        console.log("dentro del authController.post --> req.login: correcto");
        console.log("req.session.passport.user y despues req.user");
        console.log(req.session.passport.user);
        console.log(req.session);
        console.log(req.user);
        res.status(200).json(req.user);}

    });
  })(req, res, next);
});

When I do Login, in console are:

Session {
  cookie:
   { path: '/',
     _expires: 2018-10-26T08:57:02.193Z,
     originalMaxAge: 2419200000,
     httpOnly: true },
  passport: { user: 5a0492a6b004db02c32afbf0 } }

OK...

But when I do inmediatly /test (like @bogas04 the passport session is missing:


/* ---- TEST ---- */
authController.get('/test', (req, res) => {
  console.log("REQ:SESSIONSTORE: ",req.sessionStore);
  console.log("REQ.SESSIONID: ",req.sessionID);
  console.log("REQ.SESSION: ",req.session);
  res.status(200).end(req.isAuthenticated() ? 'logged in': 'logged out');
});
/* ---- TEST ----*/

The req.session is:

Session {
  cookie:
   { path: '/',
     _expires: 2018-10-26T08:51:00.438Z,
     originalMaxAge: 2419200000,
     httpOnly: true } }

And the response (with postman) to get localhost:3000/test is logged out

MuhammadHasham23 commented 5 years ago

Yeah! but you can't access req.user, can you?

JorgeJoseAbad commented 5 years ago

@MohammadHasham
undefined, In the above authcontroller.test If I'added line console.log(req.user)
its undefined Thank you

jim423 commented 5 years ago

Did you figure out what the problem is? I am having this issue. Sometimes it was fixed and then it happened again.

kamalpreetgrewal commented 5 years ago

@JorgeJoseAbad Did you find a solution to this issue? I am confronting the same issue. Looked through so many links, nothing is working out.

jim423 commented 5 years ago

@kamalpreetgrewal I fixed it by enabling credential in headers when sending login request. It’s an issue about not using CORS.

MahmoudAbdo90 commented 4 years ago

I am having the same issue, I am user Cons but still ! The thing is it is not consistent, I am using Axios for testing and I need to be logged in, once the user is attached to the session Session { cookie: { path: '/', _expires: 2018-10-26T08:57:02.193Z, originalMaxAge: 2419200000, httpOnly: true }, passport: { user: 5a0492a6b004db02c32afbf0 } }

some times it's with out the user so the cookie is not valid

anyone have any idea what to do !

MahmoudAbdo90 commented 4 years ago

I figured out what is the cause of this, using server.use( session({ cookie:blabla, resave: false, saveUninitialized: true, secret: process.env.RDS_COOKIE_SECRET, store: testEnvironment ? null : new require('connect-pg-simple')(session)() }) )

disable the store when you are sending so many login requests when testing some how causes a problem with using connect-pg-simple but now it is works just fine.

Roms1383 commented 4 years ago

I made a sample repository here in case it might help some people :) I use Nest.js, nestjs/passport with a local strategy and url redirection. Detailed article here.

reteps commented 4 years ago

I also have this issue!

ErezShahaf commented 4 years ago

same issue

colorpulse6 commented 3 years ago

Having the same issue, its been a week am I going insane?

0xOnyx commented 3 years ago

same issue please help :/

malay5-1 commented 2 years ago

Did anyone get a work around? I am facing this issue when I deploy it. I have deployed client in netlify and backend in heroku. Everything works fine when running on local as well as works with postman(the deployed version), but am still facing error on browsers. I have implemented cors, and am not getting why serialize user is not saving the session in the request.

Scandianis commented 2 years ago

Not sure if this is relevant, but I had an issue with Passport in version 0.6.0.

passport.authenticate removed id_token from request session object - with 0.5.3 the id_token was not removed.

Osama-D commented 1 year ago

hello everyone i'm coming from 2022 near 2023 and i have the same fucking issues.

0z-cryptik commented 3 months ago

here from 2024, crazy how we're still facing this issue after so many years

abhinlr commented 2 months ago

Ohh dark. I am also having the same issue. frustrated af. passport is in session when requested from postman but empty when tried from other ports.