Meteor Accounts - remember me option


#1

Hi

I know you can set amount of days the login token is valid for, something like:
Accounts.config({
loginExpirationInDays: 14
})

However I want to have a checkbox on the login form for ‘Remember me’. Basically if the user doesn’t check it, login would expire once you close the browser (session based). If user checks the checkbox it would create a token for him for let’s say 14 days. How can I do it? It seems I can’t change this value once I set it?


#2

‘Remember me’ is the default behaviour in the Accounts package, but you can use LocalStorage for this:

  • If not checked:
function () {
  Accounts.loginWithPassword();
  // stops Accounts from logging you out due to token change
  Accounts._autoLoginEnabled = false;
  // remove login token from LocalStorage
  Accounts._unstoreLoginToken();
  // if you want to synchronise login states between tabs
  var pollLoginState = function () {
    var currentLoginToken = Accounts._storedLoginToken();
    if (! currentLoginToken) return;

    // != instead of !== just to make sure undefined and null are treated the same
    if (Accounts._lastLoginTokenWhenPolled != currentLoginToken) {
      if (currentLoginToken) {
        Accounts.loginWithToken(currentLoginToken, function (err) {
          if (err) {
            Accounts.makeClientLoggedOut();
          }
        });
      } else {
        Accounts.logout();
      }
    }

    Accounts._lastLoginTokenWhenPolled = currentLoginToken;
  };

  setInterval(function () {
    pollLoginState();
  }, 3000);
}
  • If checked, login as normal

#3

Thanks a lot, works fine!


#4

Where exactly I’m supposed to put this piece of code? Thanks and sorry for the stupid question.


#5

Use it in the function where you call Accounts.loginWithPassword() on the client

So for e.g. with Blaze:

Template.loginPage.events({
  '#login-button': function () { 
    if (rememberMeCheckboxIsChecked) {
      // login as usual
    } else {
      // manage localstorage manually (with above code)
    }
  }
});

#6

Tried this but it’s not working for me. If the remember me is unchecked, user stays logged in even if window is closed and reopened.
What am I doing wrong? Is the Accounts.loginWithPassword different than Meteor.loginWithPassword?
I can see the polling is working but I don’t understand how it is supposed to work when user closes the browser and opens a new one.

Thanks for the help

Template.loginPage.events({
  '#login-button': function (event) { 
    var email = event.target.email.value;
    var password = event.target.password.value;

    if (rememberMeCheckboxIsChecked) {
        Meteor.loginWithPassword(email, password)
    } else {
        Meteor.loginWithPassword(email, password)
        Accounts._autoLoginEnabled = false;
              // remove login token from LocalStorage
        Accounts._unstoreLoginToken();
              // if you want to synchronise login states between tabs
        var pollLoginState = function () {
            var currentLoginToken = Accounts._storedLoginToken();
            if (! currentLoginToken) return;

            // != instead of !== just to make sure undefined and null are treated the same
            if (Accounts._lastLoginTokenWhenPolled != currentLoginToken) {
                if (currentLoginToken) {
                    Accounts.loginWithToken(currentLoginToken, function (err) {
                    if (err) {
                       Meteor.logout();
                    }
                    });
                } else {
                    Meteor.logout();
                }
            }

            Accounts._lastLoginTokenWhenPolled = currentLoginToken;
        };
        setInterval(function () {
            pollLoginState();
        }, 3000);
    }
  }
});

#7

This probably means the login token isn’t being removed from LocalStorage for whatever reason, so you may want to try doing it manually:

localStorage.removeItem('Meteor.loginToken');
localStorage.removeItem('Meteor.loginTokenExpires');
localStorage.removeItem('Meteor.userId');

// to ensure that the localstorage poller doesn't end up trying to
// connect a second time
Accounts._lastLoginTokenWhenPolled = null;

The localstorage key names are found here

The polling is only for keeping the same user between tabs while they have the website open (or logging them out on all tabs)

& yeah, it should be Meteor.loginWithPassword


#8

still doesn’t work. In the console, localStorage before and after the removeItem statement stays the same (token is kept). Only if I use localStorage[“Meteor.loginToken”]=null in the console and then close the browser, it indeed logs out.
Any ideas?


#9

It’s working for me, it might be your browser - your method is valid too though


#10

Meteorbeginner is right, the solution doesn’t work as is because it must be a callback in loginWithPassword, see below…

        //store in a var before logging in
        var bRememberMe = $('#htmlIdLoginRememberMe:checked').length > 0;

        Meteor.loginWithPassword(
            $('[name=htmlNameLoginEmail]').val(),
            $('[name=htmlNameLoginPassword]').val(),
            function(error){
                if(error){
                    //handle error here, no login occured
                }
                else {
                    //login occured
                    if (bRememberMe == false) {
                        //remove login token after login occured, else it doesn't work
                        Accounts._unstoreLoginToken();
                        Accounts._autoLoginEnabled = false;
                    }
                }
            }
        );

#11

This is the correct answer.
Thanks!


#12

Well, now every time I hit refresh, if the user didn’t check the ‘remember me’, it immediately logs out…
this is so frustrating, I don’t understand why simple and most straightforward features become a nightmare in Meteor.


#13

This is the correct behaviour, no? LoginToken removed = log out on session end = (page refresh || closed browser)


#14

That’s the behavior you want. You refresh, you log out.


#15

For anyone still interested in this functionality who will find the topic.

Recently I published a dependency for this:

Basically the only thing you have to change is to use a wrapper for Meteor.loginWithPassword. From now you will be able to give the rememberMe option as a last parameter to the method.

I can see issues in the previous ideas which are not there in my implementation:

  • this dependency won’t trigger any unneeded onLogin callbacks on the client/server after resume,
  • reconnecting to server won’t log out the user despite having rememberMe set as “false”

#16

Have you thought about attaching it to Meteor? For example, Meteor.loginWithPasswordAndForget(user, password, [callback])


#17

It would not be a problem to do it but personally I prefer to not do that.
I know that it can be way easier to use for people when it would be directly in the global of Meteor.
However I like the separation between modules. I feel like as long as it’s not an official Meteor thing it should not be attached to the Meteor to not confuse aynone or override something in the future by accident.

So currently if someone would want to do that then he would have to do it manually by himself like:

Meteor.loginWithPasswordAndForget = (user, password, callback = () => {}) => {
   RememberMe.loginWithPassword(user, password, callback, false);
}