maria
maria

Reputation: 159

Passport Session showing undefined req.user

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.

Upvotes: 3

Views: 12069

Answers (2)

Sarah Riehl
Sarah Riehl

Reputation: 53

When defining methods and middleware on the passport object, order matters. Your code is pretty entangled. A little decoupling will go a long way here.

  1. Move all of the strategy logic out of server.js and your passport.js. Put it in its own set of files. Also, you don't need to include the base Strategy in the server file.

  2. Define an express router in a separate file and mount the routes in your server.js

  3. passport.initialize() and passport.session() middlewares need to attach to your express app instance before you define serialize and deserialize.

  4. No need to set req.session.user, which defeats the purpose of storing just the user id in the session. On each request to express, once you deserialize the user by reading the id in req.session.passport.user, you're loading the entire user account document into req.user and you can access all user data directly from req.user.

  5. If you're using a pre-packaged passport Strategy constructor which calls done(), you don't need to call req.login anywhere.

server.js

//express, body parser, express session, etc

const app = express();
const passport = require('passport');
const user = require('./passport-serialize');
const routes = require('./routes');

//lots of middleware

//session middleware

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

passport.serializeUser(user.serialize);

passport.deserializeUser(user.deserialize);

app.use('/api', routes);

//actual server, more stuff

passport-serialize.js

//include Account model

const user = {
  serialize: (user, done) => {
    done(null, user.username)
  },
  deserialize: (username, done) => {
    Account.findOne({'username': username}, function(err, user) {
    done(err, user);
  }
}

module.exports = user;

routes.js

const express = require('express');

const router = new express.Router();

const passport = require('./strategies');

//many routes

router.post('/login', passport.authenticate('local-login'), function(req, res) {
  console.log("executed login!");
  console.log(req.user);
});

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



module.exports = router;

strategies.js

const passport = require('passport');
const LocalStrategy = require('whatever the package is');
//Account model

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
    } else 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!");
    // all is well, return successful user
    return done(null, thisuser);
  });
}));
        
 module.exports = passport;

Upvotes: 3

Suhail Gupta
Suhail Gupta

Reputation: 23206

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.

Upvotes: 3

Related Questions