0

sorry for silly question I'm using passport for authentication purpose. I wanted to logout from previous sessions (be it on different browser or device) when user tries to login with new session.

I know I can user req.logout to log out but I'm not sure how to destroy all other sessions from db which my passport is creating while login.

Even if I manually delete them, I'm not auto logging out

The following is my passport config

const passport = require('passport'),
    LocalStrategy = require('passport-local').Strategy,
    User = require('../database/Schema').User,
    shortid = require('shortid');

passport.serializeUser( (user, cb) => {
    cb(null, user);
});

passport.deserializeUser( (obj, cb) => {
    cb(null, obj);
});

passport.use('localRegister', new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    (req, email, password, done) => {
        User.findOne({$or: [{email: email}, {username: req.body.username}]},  (err, user) => {
            if (err)
                return done(err);
            if (user) {
                if (user.email === email) {
                    req.flash('email', 'Email is already taken');
                }
                if (user.username === req.body.username) {
                    req.flash('username', 'Username is already taken');
                }

                return done(null, false);
            } else {
                let user = new User();
                user.email = email;
                user.password = user.generateHash(password);
                user.username = req.body.username;
                user.stream_key = shortid.generate();
                user.save( (err) => {
                    if (err)
                        throw err;
                    return done(null, user);
                });
            }
        });
    }));

passport.use('localLogin', new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true
    },
    (req, email, password, done) => {

        User.findOne({'email': email}, (err, user) => {
            if (err)
                return done(err);

            if (!user)
                return done(null, false, req.flash('email', 'Email doesn\'t exist.'));

            if (!user.validPassword(password))
                return done(null, false, req.flash('password', 'Oops! Wrong password.'));

            return done(null, user);
        });
    }));


module.exports = passport;

The following is my user schema (I'm using mongodb)

let mongoose = require('mongoose'),
    bcrypt   = require('bcryptjs'),
    shortid = require('shortid'),
    Schema = mongoose.Schema;

let UserSchema = new Schema({
    username: String,
    email : String,
    password: String,
    stream_key : String,
});

UserSchema.methods.generateHash = (password) => {
    return bcrypt.hashSync(password, bcrypt.genSaltSync(8));
};

UserSchema.methods.validPassword = function(password){
    return bcrypt.compareSync(password, this.password);
};

UserSchema.methods.generateStreamKey = () => {
    return shortid.generate();
};

module.exports = UserSchema;

The following is my login route

const express = require('express'),
    router = express.Router(),
    passport = require('passport');

router.get('/',
    require('connect-ensure-login').ensureLoggedOut(),
    (req, res) => {
        req.logOut();
        res.render('login', {
            user : null,
            errors : {
                email : req.flash('email'),
                password : req.flash('password')
            }
        });
    });

router.post('/', passport.authenticate('localLogin', {
    successRedirect : '/',
    failureRedirect : '/login',
    failureFlash : true
}));

module.exports = router;
Ninja-aman
  • 75
  • 5
  • May be this can help: [https://stackoverflow.com/questions/51419037/one-session-per-user-passport-js](https://stackoverflow.com/questions/51419037/one-session-per-user-passport-js) – Hritik R Mar 11 '23 at 05:47
  • @HritikR no it didn't, I looked into it but it didn't work – Ninja-aman Mar 11 '23 at 06:00

2 Answers2

0

You can use Express-session package for store the value in databases. Because Express-session delete the value automatically from database after expire time. https://www.npmjs.com/package/express-session

MD SHEHAB
  • 11
  • 1
0

according to the source file, logout session manager, you can add key keepSessionInfo as option.

//https://github.com/jaredhanson/passport/blob/master/lib/sessionmanager.js#L83-L91
req.session.regenerate(function(err) {
  if (err) {
    return cb(err);
  }
  if (options.keepSessionInfo) {
    merge(req.session, prevSession);
  }
  cb();
});

that function also applied to login.

it would be like:

passport.authenticate('actionName', {
  ...,
  keepSessionInfo : false
})

in your case, you better to put it on action login, because logout will delete the last one session as well.

base on your code, it would be:

router.post('/', passport.authenticate('localLogin', {
    successRedirect : '/',
    failureRedirect : '/login',
    failureFlash : true,
    keepSessionInfo : false //added here.
}));
Tobok Sitanggang
  • 607
  • 5
  • 15
  • Thanks @Tobok for your reply, but it is not working somehow. I'm still able to login in two devices and I can see different sessions being created in db – Ninja-aman Mar 12 '23 at 12:36
  • according to the doc, its should be initiated when app running, so if you already have an user that have multiple session, try to create a new one. – Tobok Sitanggang Mar 12 '23 at 12:52
  • I tried. I deleted all the sessions and users, made the changes you suggested and then tried again. Still no luck. I appreciate your suggestions. – Ninja-aman Mar 12 '23 at 17:51
  • well, there is another way. you can store to db an `unique id` when logging in, and check if the `unique id !== null`. and when logout, set it `null`. or you can store it to `redis` with expiry time for better approach. so you dont have to worry about those stuff again. – Tobok Sitanggang Mar 12 '23 at 19:57