I've created a simple Authentication application with passport (see code below). Express through the session middleware, creates a session on every request where the requesting client does not have a session already. I'd like to assign sessions only after logging or create a new session after login.
This is because I will eventually be doing login over HTTPS and would like to prevent hackers from hijacking the sessions from users that have authenticated.
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 Passport local strategy I tried to use req.session.regenerate() or req.session.reload() when the user was successfully validated against the database but that 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's 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);
});
});
}));
};
After digging into passports and express-sessions library, I've figured it out!
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 let passport do its authentication first, where it attaches an object onto req.session.passport. Passport uses this object to find out the mapping from session -> userId on further requests. When you regenerate the session, the req.session.passport object gets lost. Thus, you have to make sure to transfer it over to the newly generated session, and save it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With