Make sure user is logged into only one tab?

Hey, if people log into my app from more than one tab/browser they’re going to have problems.

So, when a user logs in, I’d like to log them out everywhere else, and park them on a “you logged in somewhere else” page.

I tried a couple things: Accounts.logoutOtherClients() looked promising, but seems to be broken. This logs everyone out.

if (Meteor.isClient) {
  // FF 1 tab, Chrome 2 tabs.
  // FF login -> chrome logs out ok.
  // Chrome login -> FF logs out.  Then Chrome other tab logs in.  Then both Chrome tabs logout.
  Accounts.onLogin(function() {
    console.log(Meteor.loggingIn()); // false.  See https://github.com/meteor/meteor/issues/1616
    Accounts.logoutOtherClients();
  });
}

Before that I was working on a hand-rolled solution, but it seemed like Meteor.logout() would logout both tabs in the same browser. The best I could get was window.location="https://google.com"

NOTE: The approach below doesn’t work if user closes all tabs. When they re-open app, they can never login again.

What’s the way to do this?

The best way I can think to do this is:

  1. At Meteor.start() on the client make a unique tabToken
  2. Save token to Session variable on client
  3. At login save tabToken to user
  4. On client, listen to Meteor.user().profile for tabToken changes.
if (Meteor.isClient) {

  // Make a unique tabToken at startup.
  Meteor.startup(function() {
    var tabToken = (0|Math.random()*9e6).toString(36);  // jshint ignore:line
    Session.set('tabToken', tabToken);
    console.log('startup TabToken ' + Session.get('tabToken'));
  });

  // onLogin, set the active tab to our tabToken
  Accounts.onLogin(function() {
    Meteor.call('setActiveTab', Session.get('tabToken'), function() {
      // When method returns, watch profile for tabToken changes
      console.log('setActiveTab tabToken ' + Session.get('tabToken'));
      console.log('setActiveTab Meteor.user().profile.tabToken ' + Meteor.user().profile.tabToken);

      Tracker.autorun(function (c) {
        // If the tabToken changes to a different token, logout
        if (Meteor.user()) {
          var userTabToken = Meteor.user().profile.tabToken;
          if (userTabToken && !Session.equals('tabToken', userTabToken)) {
            window.location = 'https://google.com';
            // Doesn't work
            // c.stop();
            // Meteor.logout(); // ERROR this logs out all tabs in browser.
            // Router.go('loggedOut');
          }
        }
      });
    });
  });
}

// Make a meteor method to set tabToken
if (Meteor.isServer) {
  Meteor.methods({
    setActiveTab: function(tabToken) {
      if(!tabToken) throw new Meteor.Error('noTabToken');
      console.log('setActiveTab ' + tabToken);
      if (!Meteor.user()) return;
      Meteor.users.update(Meteor.userId(), {
        $set: {
          'profile.tabToken': tabToken
        }
      });
    }
  });
}

This just seems really kludgy. Any other suggestions?

Mike

1 Like

I would not mess with the login part but just add a value to the user record and also add that value (a unique nr) into the session. If equal you can use the app, otherwise you see a locked screen. When you click a button on the lock screen you take over the app (set new random nr in both user and session.

2 Likes