loginExpirationInDays - set per user

I know of the loginExpirationInDays config option and have read through this: Meteor Auto Logout [Solved] - though it is marked as solved so starting a new one with a slightly different ask.

Is there a way to set the loginExpirationInDays to be different for each user (vs a global config option for all users)?

Cheers for anyone who knows or might have any ideas…

With no replies I imagine there is no ‘standard’ way to do this.

How does this work as a hacky way to do it:

  1. On login, set the login date to local storage
  2. Every time the app mounts, check local storage, and if:
 currentDate > localStorageDate + userLogoutPreference 

Then run Meteor.logout()…?

Pitfalls that I see/comments:

  1. This is obviously not a security guarantee because it is client side storage and js that can easily be modified - is there any fix to that?
  2. It adds a simple layer of security because for an exploit, one would have to know that a previous user was logged in, failed to log out and then modify the js/localstorage prior to visiting the site

Thoughts/comments appreciated

Sorry bud - totally meant to reply to this earlier. We ended up using:

import { TimeSync } from 'meteor/mizzao:timesync';
import { UserStatus } from 'meteor/mizzao:user-status';

And using a componentDidMount (react) like so:

export class App extends Component {
  @observable showIdleDialog = Boolean(false);
  @observable secondsToLogout = 15;
  @observable intervalHandler = null;

  componentDidMount() {
    const {threshold, interval, idleOnBlur} = Meteor.settings.public['inactivity'];

    Tracker.autorun(async () => {
      if (Meteor.userId() &&  !UserStatus.isMonitoring() && TimeSync.isSynced()) {
        await UserStatus.startMonitor({threshold, interval, idleOnBlur});
      }
    });

    Tracker.autorun(() => {
      if (Meteor.userId() && UserStatus.isMonitoring() && UserStatus.isIdle() && !this.intervalHandler) {
        this.showIdleDialog = Boolean(true);
        this.intervalHandler = Meteor.setInterval(() => {
          this.secondsToLogout--;
          if (this.secondsToLogout <= 0) {
            this.handleTouchTapClose();
            Meteor.logout(() => {
              UserStatus.stopMonitor();
              browserHistory.push('/login');
            });
          }
        }, 1000);
      }
    });
  }

  renderDialogActions() {
    return (
      <FlatButton
        label='Continue'
        primary={true}
        onClick={this.handleTouchTapClose.bind(this)}
      />
    );
  }

  handleTouchTapClose() {
    this.showIdleDialog = false;
    this.secondsToLogout = 15;
    Meteor.clearInterval(this.intervalHandler);
    this.intervalHandler = null;
  }

  render() {
    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>
        <span>
          <AppNavigation />
          { this.props.children }
          <Dialog
            title="You will be logged out soon"
            actions={this.renderDialogActions()}
            open={this.showIdleDialog}
            onRequestClose={this.handleTouchTapClose.bind(this)}
          >
            {`You will be logged out in the next ${this.secondsToLogout} seconds if you don't perform any activity.`}
        </Dialog>
        </span>
      </MuiThemeProvider>
    );
  }
}

The key point here is that we don’t really use the loginExpirationInDays: 365 part. Its in the background, but we are using a 15 min timeout to kick the user out on inactivity. I’d use something similar in the background, and also check a db entry somewhere which has the custom per user time outs. That way, you can warn users to reset their passwords if they are getting close to their custom expiration’s etc.

3 Likes

:+1:

Thanks for that! Useful to know those packages - looking over how they work and your code snippet, it does seem to be following a similar sort of principle. I.e - monitor inactivity and call logout on the client if it surpasses a certain amount.

I’ll give it a go and put up the code I come up with here.

Ps - Have never seen the @observable syntax you have on your snippet either. Some reading/learning for me to do

Cheers!

So whats happening here is a mobX pattern. Essentially, instead of using a redux pattern with react, i use a observable pattern, which allows me to make up lots of reactive stores (as in, mobx manages state for me instead of setState).

I’ma big fan of the pattern, its worked really well for me. However, does cause some issues with eslint and jsdoc etc.

Wow this really saved me.

Thank for sharing

1 Like