Creating a new session after authentication with a passport

I created a simple authentication application with a passport (see code below). Express through the session middleware creates a session for each request in which the requesting client does not have a session. I would like to assign sessions only after registering or creating a new session after logging in.

This is because I will ultimately log in via HTTPS and would like to prevent hackers from hijacking sessions from authenticated users.

Here is my server code:

// Server.js configures the application and sets up the webserver //importing our modules var express = require('express'); var app = express(); var port = process.env.PORT || 8080; var mongoose = require('mongoose'); var passport = require('passport'); var flash = require('connect-flash'); var MongoStore = require('connect-mongo')(express); var configDB = require('./config/database.js'); //Configuration of Databse and App mongoose.connect(configDB.url); //connect to our database require('./config/passport')(passport); //pass passport for configuration app.configure(function() { //set up our express application app.use(express.logger('dev')); //log every request to the console app.use(express.cookieParser()); //read cookies (needed for auth) app.use(express.bodyParser()); //get info from html forms app.set('view engine', 'ejs'); //set up ejs for templating //configuration for passport app.use(express.session({ secret: 'olhosvermdfgytuelhoseasenhaclassica', cookie: { maxAge: 120000 }, store: new MongoStore({ db: 'xYrotr4h', host: 'novus.modulusmongo.net', port: 27017, username: 'gdog', password: 'fakepassowrd123' }) })); //session secret + expiration + store app.use(passport.initialize()); app.use(passport.session()); //persistent login session app.use(flash()); //use connect-flash for flash messages stored in session }); //Set up routes require('./app/routes.js')(app, passport); //launch app.listen(port); console.log("Server listening on port" + port); 

In my new local Passport strategy, I tried using req.session.regenerate () or req.session.reload () when the user was successfully verified against the database, but this caused the server to crash.

Here is how I define my strategy:

 //Passport.js sets up our local strategies //imports var LocalStrategy = require('passport-local').Strategy; var User = require('../app/models/user'); //export this as a module since we give it to passport module.exports = function(passport) { //Set up the session for persistent login passport.serializeUser(function(user, done) { done(null, user.id); }); //used to serialize the user passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); //setting up local sign up passport.use('local-signup', new LocalStrategy({ //by default, the local strategy uses usernames and password, we will override with email usernameField: 'email', passwordField: 'password', passReqToCallback: true }, function(req, email, password, done) { console.log("Callback ran!"); //asynchronous //User.findOne wont fire unless data is sent back process.nextTick(function() { console.log("I did run!"); //find user whose email is the same as form email // we are checking to see if the user trying to sign up already exists User.findOne({ 'local.email': email }, function(err, user) { //if there any errors, return the errors if (err) { return done(err); } //check to see if there any users already with that email if (user) { return done(null, false, req.flash('signupMessage', 'That email is already taken.')); } else { console.log('New user will be added to the DB!'); //if there is no user with that e-mail, create the user var newUser = new User(); //we set the user local credentials newUser.local.email = email; newUser.local.password = newUser.generateHash(password); //save the user in the store newUser.save(function(err) { if (err) { throw err; } return done(null, newUser); }); } }); }); })); // ========================================================================= // LOCAL LOGIN ============================================================= // ========================================================================= // we are using named strategies since we have one for login and one for signup // by default, if there was no name, it would just be called 'local' passport.use('local-login', 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, email, password, done) { // callback with email and password from our form // 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 User.findOne({ 'local.email' : email }, function(err, user) { // if there are any errors, return the error before anything else if (err) return done(err); // if no user is found, return the message if (!user) return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash // if the user is found but the password is wrong if (!user.validPassword(password)) return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata // all is well, return successful user // removing the req.session.regenerate fixes any crashing req.session.regenerate(function(err, done, user){ return done(null, user); }); }); })); }; 
+7
authentication session
source share
4 answers

After digging into passports and express session libraries, I realized that!

 var session = function (req, res) { var temp = req.session.passport; // {user: 1} req.session.regenerate(function(err){ //req.session.passport is now undefined req.session.passport = temp; req.session.save(function(err){ res.send(200); }); }); }; app.post('/login', passport.authenticate('local'), session); 

Basically, I allow the passport to first authenticate it, where it attaches the object to req.session.passport. The passport uses this object to search for a match from the session → userId for further queries. When you restore a session, the req.session.passport object is lost. Therefore, you must definitely transfer it to the newly generated session and save it.

+18
source share

It seems that Jared does not want to support this directly on the basis of issue # 194 , with which I am not sure that I agree - at least the passport should set its own session regeneration function. In any case, you can solve this in the general case by replacing:

 req.session.regenerate(function(err, done, user){ return done(null, user); }); 

with something like this:

 var passport = req._passport.instance; req.session.regenerate(function(err, done, user) { req.session[passport._key] = {}; req._passport.instance = passport; req._passport.session = req.session[passport._key]; return done(null, user); }); 
0
source share

Real example from the open source project Gitter.im: https://gitlab.com/gitlab-org/gitter/webapp/commit/44bb6d8934bce37b86d4ee3fcdba759967a5e5c1

In detail about Stephen Young :

In case you have several strategies with custom callbacks , you want to create a separate method (for example, passportLogin ) that will eventually call req.login :

 //passportLogin.js async function regeneratePassportSession(req) { const passportSession = req.session.passport; return new Promise((resolve, reject) => req.session.regenerate(function(err) { if (err) reject(err); assert(!req.session.passport); req.session.passport = passportSession; req.session.save(function(err) { if (err) reject(err); resolve(); }); }) ); } /** * Adds user to passport, if this is the * first time (user just logged in) we generate a new session * and returns a user with identity object */ module.exports = async function passportLogin(req, user) { // if user just logged in (session hasn't been authenticated before) if (!req.user) await regeneratePassportSession(req); await new Promise((resolve, reject) => { req.login(user, err => { if (err) reject(err); resolve(); }); }); return user; 

And call it in every strategy.

0
source share

I think you need to replace:

 req.session.regenerate(function(err, done, user){ return done(null, user); }); 

from:

  req.login(user, function(err) { if (err) return res.status(500).send('error'); return done(null,user); }); 

req.login internally calls your passport.serializeUser() function.

-one
source share

All Articles