Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session auto logout after inactivity

Is there a built in feature in express session, to enable auto logout after given time of inactivity ? I am using it as below, and want it to logout if session is inactive for half an hour.

app.use(session({
  key: 'sessid',
  secret: 'This is secret',
  resave: true,
  saveUninitialized: true,
  store: new RedisStore(redisOptions),
  cookie: {
    path: '/',
    httpOnly: true,
    secure: false,
    maxAge: 24 * 60 * 60 * 1000,
    signed: false
  }
}))
like image 677
nishant pathak Avatar asked Jul 01 '16 11:07

nishant pathak


2 Answers

Ok, I'll throw my two cents into the ring here.

Even though it's in theory possible to implement this using rolling session, I don't think you should...

  • It would require each user action the send a request to the server, in order for the user not to be logged out.
  • You miss an opportunity to inform your user that he/she will be logged out automatically soon (this is what the banks do, for example).
    @Seth did point out in a comment above that there is actually a way to remedy this: "If the front end is separate from the server, you could have client side routing middleware that checks the cookie and visually logs you out, thus proving a good UX."
    I think this is clever, but I also think it's like putting lipstick on a pig.

I believe that the best approach here is to handle this on the client side.

I would suggest something like this:

var AutoLogout = (function() {
  function AutoLogout() {
    this.events = ['load', 'mousemove', 'mousedown',
                   'click', 'scroll', 'keypress'];

    this.warn = this.warn.bind(this);
    this.logout = this.logout.bind(this);
    this.resetTimeout = this.resetTimeout.bind(this);

    var self = this;
    this.events.forEach(function(event) {
      window.addEventListener(event, self.resetTimeout);
    });

    this.setTimeout();
  }

  var _p = AutoLogout.prototype;

  _p.clearTimeout = function() {
    if(this.warnTimeout)
      clearTimeout(this.warnTimeout);

    if(this.logoutTimeout)
      clearTimeout(this.logoutTimeout);
  };

  _p.setTimeout = function() {
    this.warnTimeout = setTimeout(this.warn, 29 * 60 * 1000);

    this.logoutTimeout = setTimeout(this.logout, 30 * 60 * 1000);
  };

  _p.resetTimeout = function() {
    this.clearTimeout();
    this.setTimeout();
  };

  _p.warn = function() {
    alert('You will be logged out automatically in 1 minute.');
  };

  _p.logout = function() {
    // Send a logout request to the API
    console.log('Sending a logout request to the API...');

    this.destroy();  // Cleanup
  };

  _p.destroy = function() {
    this.clearTimeout();

    var self = this;
    this.forEach(function(event) {
      window.removeEventListener(event, self.resetTimeout);
    });
  };

  return AutoLogout;
})();

es2015

class AutoLogout {
  constructor() {
    this.events = ['load', 'mousemove', 'mousedown',
                   'click', 'scroll', 'keypress'];

    this.warn = this.warn.bind(this);
    this.logout = this.logout.bind(this);
    this.resetTimeout = this.resetTimeout.bind(this);

    this.events.forEach((event) => {
      window.addEventListener(event, this.resetTimeout);
    });

    this.setTimeout();
  }

  clearTimeout() {
    if(this.warnTimeout)
      clearTimeout(this.warnTimeout);

    if(this.logoutTimeout)
      clearTimeout(this.logoutTimeout);
  }

  setTimeout() {
    this.warnTimeout = setTimeout(this.warn, 29 * 60 * 1000);

    this.logoutTimeout = setTimeout(this.logout, 30 * 60 * 1000);
  }

  resetTimeout() {
    this.clearTimeout();
    this.setTimeout();
  }

  warn() {
    alert('You will be logged out automatically in 1 minute.');
  }

  logout() {
    // Send a logout request to the API
    console.log('Sending a logout request to the API...');

    this.destroy();  // Cleanup
  }

  destroy() {
    this.clearTimeout();

    this.events.forEach((event) => {
      window.removeEventListener(event, this.resetTimeout);
    });
  }
}

Partial polling solution:

var activityPolling = (function() {
  var events = ['load', 'mousemove', 'mousedown', 'click', 'scroll', 'keypress'];
  var active = true;
  var timeout;

  function poll() {
    if(active) {
      console.log('polling the server...')
    }
  }

  function setIdle() {
    active = false;
  }

  function setActive() {
    active = true;
    if(timeout)
      clearTimeout(timeout);
    timeout = setTimeout(setIdle, 30 * 60 * 1000);
  }

  function destroy() {
    clearInterval(interval);

    events.forEach(function(event) {
      window.removeEventListener(event, setActive);
    });
  }

  events.forEach(function(event) {
    window.addEventListener(event, setActive);
  });

  setActive();

  var interval = setInterval(poll, 60 * 1000);

  return {
    interval: interval,
    destroy: destroy
  }
})();
like image 177
demux Avatar answered Oct 11 '22 03:10

demux


Rolling session may solve the purpose.

If you use the "rolling" option for session to "true," it will update the session timeout on new requests.

What you can do is: set max-age to 5 minutes.

 maxAge: 30*10000

When there is no activity max-age will destroy the session. However, when there is any activity, rolling will renew the session to be alive for next 30 minutes.

Again, the word in-activity in this question is little misleading. In-activity could be any (or all) of no-mouse-movement, no-mouse-click, or no-interaction-with-server.
If you refer inactivity as no-interaction-with-server, this logic will work. However for no-ui-interactions inactivity, you need to handle from client side

like image 44
Ritesh Kumar Gupta Avatar answered Oct 11 '22 04:10

Ritesh Kumar Gupta