How we implemented Auto Logout client side

Sean Nicholas
3 min readMar 15, 2017

--

Our goal was to write a function that automatically logs out a user after 5 minutes. We decided to implement this feature client side because we didn’t need the added security by creating new tokens on the server every time a user requests a resource. Further we use an Angular2 SPA. Therefore, not every interaction with the application involves a server request, resulting in no timer reset and may cause confusion.

We discovered the following requirements:

  • A user must be logged out after 5 minutes.
  • Every (click) interaction must reset the timer.
  • The timer must be synchronized between tabs.
  • If a user closes the tab before the timer expires she gets logged out when she visits the page again.

Implementation

As you can see our service is pretty straight forward. Not much magic happening ;)

First of all we use store.js to access the localStorage because there are still browsers lacking support. (I’m looking at you Safari (in private mode) — IE of modern days -.-)

We define some constants for later use and define the AutoLogoutService class.

The getter retrieves the lastAction from localStorage. Because it is saved as string we need to parse it to an integer.

We inject the authService from outside. In our case it must have a logout function and a loggedIn property.

The click listener is easy: On every click lastAction is set to the current timestamp.

Every CHECK_INTERVAL (1000ms) this.check() gets called and calculates the time left and the difference to the current time. If it is negativ (no more time left) and the user is logged in he gets logged out.

You may miss a function to get the time left to display it in the GUI. I didn’t include it in this demonstration for better readability.

Performance

Wait, are they using localStorage????? But that is synchronous and blocking!!!11

Well, you are right. But it turns out that getting an item from localStorage once in a second and setting one on every click isn’t as bad as you’d think. On a low end device (tested with Google Chrome’s CPU throttling) the periodic check took on average 0.28ms (measured with console.time on example.com without any interactions / 44 samples). The click listener took on average 0.39ms (every 250ms a click, simulated with document.body.click() / 88 samples).

I think for most use cases this is fast enough. But because this tests is somewhat artificial we tried the code in our app and didn’t notice any slowdown.

Angular2 Fixes

Well, actually we noticed a slowdown but it wasn’t caused by localStorage and we could fix it quit easily. We use the default Angular2 change detection in our app. It hooks into every async function in the browser and triggers a change detection (CD) whenever such a function has been performed. And as you might have thought setInterval is async.

Therefore every second a complete CD is triggered causing the app to slow down. The solution is pretty easy and straight forward. Just wrap setInterval and the click listener into ngZone.runOutsideAngular(). As the name suggests it runs our code outside of angular and no CD is performed. But we need to tell Angular when a user gets logged out. Luckily ngZone has the run() function in which we wrap this.auth.logout() to trigger a CD again.

If you want to learn more about Angular2 Change Detection check out this blogpost by thoughtram.

That’s it. Pretty easy ;)

If you found a bug in our code or an edge case we didn’t consider, let us know in the comments. Would you have implemented it in another way? Tell us how and why. We love to hear and learn from other approaches.

EDIT: Final code

As pointed out in the comments, I never showed the complete code with the ngZone stuff and how the service should be used. So here it is. If you have any questions please write them in the medium comments as I don’t get notified about gist comments.

--

--