Passport Session showing undefined req.user

maria picture maria · May 3, 2017 · Viewed 8.2k times · Source

When im logging in the req.user is displayed as it should, but after navigating to /test , the req.user is undefined.

Why is that?

server.js

var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session      = require('express-session');
var router = express.Router();
var Account = require('src/app/models/Users.js');
var Core = require('/src/app/gamemodels/core');
// Init passport authentication
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
require('/src/config/passport')(passport);
var cookieParser = require('cookie-parser')



// required for passport session

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect('DB');
app.use(cookieParser()) // required before session.

app.use(session({ secret: 'xxxx' }));
app.use(passport.initialize());
app.use(passport.session());






var port = process.env.PORT || 3000;        // set our port


// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
    res.json({ text: 'hooray! welcome to our api!' });
});


router.get('/test', function(req,res) {
    console.log(req);
    console.log(req.user);
    res.json(req.user);
});


router.post('/signup', passport.authenticate('local-signup', {
    successRedirect : '/profile', // redirect to the secure profile section
    failureRedirect : '/signup', // redirect back to the signup page if there is an error
}));

router.post('/login', passport.authenticate('local-login'), function(req, res) {

    console.log("executed login!");
    console.log(req.user);
    req.session.user = req.user;

});


});
*/



// more routes for our API will happen here

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);

// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);

passport js:

// config/passport.js

// load all the things we need
var LocalStrategy   = require('passport-local').Strategy;

// load up the user model
var Account = require('src/app/models/Users.js');

// expose this function to our app using module.exports
module.exports = function(passport) {

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

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        Account.findById(id, function(err, user) {
            done(err, user);
        });
    });

    passport.use('local-login', new LocalStrategy({
            // by default, local strategy uses username and password, we will override with email
            usernameField : 'username',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) { // callback with email and password from our form
            console.log("doing local login");
            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            Account.findOne({ 'username' :  username }, function(err, user) {
                var thisuser = user;
                console.log("query account is done");
                // if there are any errors, return the error before anything else
                if (err) {
                    console.log("error occured");
                    return done(err);
                }

                console.log("if user exist check");


                // if no user is found, return the message
                if (!user)
                    return done(null, false,'No user found.'); // req.flash is the way to set flashdata using connect-flash


                console.log("checking password");
                // if the user is found but the password is wrong
                if (!user.validPassword(password)) {
                    console.log("password is not valid");
                    return done(null, false, 'Oops! Wrong password.'); // create the loginMessage and save it to session as flashdata

                }
                console.log("all good! logging in!");


                req.login(thisuser, function(error) {
                    if (error) return next(error);
                    console.log("Request Login supossedly successful.");
                });

                // all is well, return successful user
                return done(null, thisuser);
            });

        }));

    passport.use('local-signup', new LocalStrategy({
            // by default, local strategy uses username and password, we will override with email
            usernameField : 'email',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {
            process.nextTick(function() {
                    console.log("doing local signup");
                // find a user whose email is the same as the forms email
                // we are checking to see if the user trying to login already exists
                Account.findOne({ 'username' :  username }, function(err, user) {
                    // if there are any errors, return the error
                    if (err)
                        return done(err);

                    // check to see if theres already a user with that email
                    if (user) {
                        return done(null, false, 'That username is already taken.');
                    } else {

                        var newUser            = new Account();

                        // set the user's local credentials
                        newUser.username    = username;
                        newUser.password = newUser.encryptPassword(password);

                        // save the user
                        newUser.save(function(err) {
                            if (err)
                                throw err;
                            return done(null, newUser);
                        });
                    }

                });

            });

        }));

};

EDIT1:

changed passport.js serialize function and deserialize function to the following:

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

// used to deserialize the user
passport.deserializeUser(function(username, done) {
    Account.findOne({'username': username}, function(err, user) {
        done(err, user);
    });
});

still did not make any difference. Undefined still occur.

EDIT2:

value of user in serializing:

{ _id: 5909a6c0c5a41d13340ecf94,
  password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
  username: 'admin',
  __v: 0,
  inFamily: false,
  bank: 500,
  cash: 2500,
  xp: 0,
  rank: 1,
  bullets: 0,
  location: 1,
  permission: 0,
  health: 100 }

edit3:

changed the login func to:

router.post('/login', passport.authenticate('local-login'), function(req, res) {

    console.log("executed login!");
    console.log(req.user);
    req.session.user = req.user;
    req.logIn(req.user, function (err) {
        if (err) {
            return next(err);
        }

    });

});

server log response:

doing local login
query account is done
if user exist check
checking password
all good! logging in!
serializing!
Request Login supossedly successful.
serializing!
executed login!
{ _id: 5909a6c0c5a41d13340ecf94,
  password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
  username: 'admin',
  __v: 0,
  inFamily: false,
  bank: 500,
  cash: 2500,
  xp: 0,
  rank: 1,
  bullets: 0,
  location: 1,
  permission: 0,
  health: 100 }
serializing!

still no sign to unserialize log.

Answer

Suhail Gupta picture Suhail Gupta · May 3, 2017

The reason is that you are missing on the deserialization part.

    /**
     * Each subsequent request will contain a  unique 
     * cookie that identifies the session. In order to support login sessions, 
     * Passport will serialize and deserialize user instances to and from the session.
     */
    passport.serializeUser(function (user, done) {
        done(null, user.username);
    });

    passport.deserializeUser(function (username, done) {
        /**
         * Necessary to populate the express request object with
         * the 'user' key
         * Requires(*):
         *  - session support with express
         *  - call to logIn from passport.auth)enticate if using authenticate
         *   callback.
         */
        // TODO: Verify if username exists
        done(null, username);
    });

So after the user is authenticated or when req.isAuthenticated() is true, the deserialization middleware function will be invoked and will update the request object with username or req.user in your case.

Reference:

Since you are using a custom callback to handle success or failures, it becomes the application's responsibility to establish a session by calling req.logIn. So after the user is authenticated, add

req.logIn(user, function (err) {
    if (err) { return next(err); }
    return { // Do a redirect perhaps? }
});

Refer to section Custom Callbacks in the reference link, I gave you.