Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I remove all sessions from one user? #201

Closed
aralroca opened this issue Nov 16, 2015 · 10 comments
Closed

How can I remove all sessions from one user? #201

aralroca opened this issue Nov 16, 2015 · 10 comments
Labels

Comments

@aralroca
Copy link

Question:
How can I remove all sessions from one user?
Thanks!

@jdesboeufs
Copy link
Owner

There is no concept of user in connect-mongo.
But if you save a property user in the session, you can easily write a remove request through the MongoDB driver.

Example:

db.sessions.remove({ 'session.user': VALUE });

@aralroca
Copy link
Author

Thank you!

@jdesboeufs
Copy link
Owner

You will need to set stringify option to false.

@Madhu94
Copy link

Madhu94 commented Apr 27, 2016

How do you set the property "user" in the sessions? I'm using mongoose 4.x and node 0.10. I'm trying to set it like this :
app.use(session(store:new MongoStore({
url: conn_string,
stringify:false
}),
//store :sessionStore,
secret: 'hello',
user:"me"});
But its not persisted in the sessions collection.

@jmcollin78
Copy link

I'm also interested by this feature. What is the best way to access to the MongoDriver without instantiating a new one ?
Another question : is this an interesting feature you could add to the product in a future release ? I'm sure many people could be interested.

@jdesboeufs
Copy link
Owner

@jmcollin78: The db instance is accessible through store.db.

@Madhu94: You can't set any default attribute in the constructor.
You have to execute your own request if you want to interact with an hypothetic user attribute.

@jmcollin78
Copy link

jmcollin78 commented Jul 25, 2016

@jdesboeufs Many thank's for your answer. For those who can be interested, I've implemented this feature with ouathtoken and passport with this piece of code:

exports.requiresRemoveOldSession = function (req, res, next) {
    log.info('Into requiresRemoveOldSession');
    var userId = req.user ? req.user.id : undefined;
    if (!userId) {
        log.info('No user found in req. Exiting');
        return next();
    }
    log.info('Remove all existing sessions of userId "%s" but not the session with id "%s"', userId, req.sessionID);
    var store = req.sessionStore;
    //    log.info('store.db is "%s"', dbg(store.db));
    var sessionsColl = store.db.collection('sessions');
    var oauthTokenColl = store.db.collection('oauthtokens');
    //    log.info('collection is "%s"', dbg(sessionsColl));
    // check all oauthtokens in the header to delete it
    var authorization = req.headers.authorization;
    if (authorization) {
        var bearer = authorization.split(' ')[1];
        log.info('Removes all oAuthTokens but not this one "%s"', bearer);
        oauthTokenColl.remove({
            'accountId': req.user.email,
            'type': 'AccessToken',
            'token': {
                '$ne': bearer
            }
        }, function (err, nbDeleted) {
            if (err) log.error('Cannot remove oAuthTokens cause "%s"', err);
            else log.info('We have removed "%d" access tokens from oAuthTokens', nbDeleted);
        });
    } else {
        log.info('Removes all oAuthTokens');
        oauthTokenColl.remove({
            'accountId': req.user.email,
            'type': 'AccessToken'
        }, function (err, nbDeleted) {
            if (err) log.error('Cannot remove oAuthTokens cause "%s"', err);
            else log.info('We have removed "%d" access tokens from oAuthTokens', nbDeleted);
        });
    }

    log.info('Req.headers="%s"', dbg(req.headers));
    sessionsColl.find({
        'session.passport.user': userId,
        '_id': {
            '$ne': req.sessionID
        }
    }, { _id : 1 }).toArray(function (err, userSessions) {
        log.info('UserSessions to remove are "%s"', dbg(userSessions));
        _.forEach(userSessions, function (userSession) {
            log.info('We will remove session "%s"', dbg(userSession));
            store.destroy(userSession._id, function (err) {
                if (err) log.error('Cannot remove session "%s" cause "%s"', userSession._id, err);
                else log.info('Session "%s" removed successfully', userSession._id);
            });
        });
        next();
    });
};

Of course you will need to adapt this to your case.
I hope this help !

JM.

@wyckster
Copy link

Sorry for the late drive-by question, but what happens if there is a cluster? If there are other workers in the cluster that are using the session, are they using an in-memory cached version of the session or does it actually hit the mongodb every time? Where's the caching handled? I'm worried that removing the session documents from the mongodb won't actually invalidate the session for other nodes in the cluster due to caching. Do you need redis or something to tell the other workers in the cluster to invalidate their session cache? Is there even a session cache? This seems like it can't work without something like redis. Does it really work just to delete the session documents? Feel free to tell me otherwise.

@grundb
Copy link

grundb commented Jul 25, 2020

@wyckster did you end up finding a solution to this problem?

@nesro
Copy link

nesro commented Apr 13, 2023

If you are reading this, you might wonder what is the solution if you have stringify as true (which is the default value).

One easy way is to have separate collection of active sessions with:

  • sessionId
  • timestamp
  • userId (indexed)

then, with every new login, you will add a record to this collection.

Then, deleting all sessions from a single user is easy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants