avatarThi Tran

Summary

This article provides a comprehensive guide on implementing an idle timeout mechanism in web applications to automatically log out inactive users, ensuring data security across multiple browser tabs using JavaScript, React, Angular, and other frameworks.

Abstract

The article titled "How to detect inactive user to auto logout by using idle timeout in JavaScript, React, Angular and more?" addresses the critical need for web applications to safeguard user data by automatically logging out users who have been inactive for a set period. It outlines a method that tracks user activity through mouse movements, clicks, and keyboard inputs and synchronizes the idle state across multiple browser tabs. The solution involves creating an IdleTimer class that updates expired time in localStorage, uses intervals to check for inactivity, and provides a callback for when the timeout is reached. The article also discusses performance optimizations and ensures that the idle state is correctly managed even when the user closes and reopens the application window. Demonstrations using React and Angular are provided to illustrate the implementation, with full code examples available on Codesandbox for developers to reference and adapt for their specific needs.

Opinions

  • The author emphasizes the importance of protecting user data, particularly in applications handling sensitive information.
  • The proposed solution is designed to be framework-agnostic, with a focus on using pure JavaScript, making it widely applicable to various web development environments.
  • The article suggests that simply using setTimeout is insufficient for multi-tab scenarios, necessitating a more robust approach to idle detection.
  • Performance considerations are highlighted, with recommendations to avoid excessive expired time updates during user interactions.
  • The author provides a practical example of how to integrate the IdleTimer class into a React application, demonstrating the ease of implementation and integration with modern web frameworks.
  • Encouragement is given to developers to extend the IdleTimer class for use with other frameworks, promoting reusability and adaptability of the solution.
  • The article invites feedback and collaboration from the developer community, indicating an openness to improve the technique and address potential challenges faced by developers.

How to detect inactive user to auto logout by using idle timeout in JavaScript, React, Angular and more?

Picture: unsplash.com/@neonbrand

Imagine you have an application in which users have some sensitive data and they may forget to logout, leave the session open and someone else can extract these sensitive data like a banking account, personal information, private messages,…

As a developer, you need to have a solution to protect our users when they are leaving for a while to drink water, to have a phone call, or to be in the restroom,…

This post is not only for React developers but also for others who are using other JavaScript frameworks because we will be focusing on problem solving with pure JavaScript rather than using a specific framework.

Let’s get started!

How to detect inactive users?

Inactive users means they don’t interact with our application for a while when they are leaving or switching to another browser tab. From a technical perspective, it should be tracking activity by mouse move, mouse click, scroll, or keyboard input.

How to implement an idle timer for inactive users?

When we hear about the timeout, I’m pretty sure that you will think about using setTimeout method in this context. And yes, it’s the simplest way to implement the timeout on the browser by the following steps:

  • Call setTimeout(<logoutMethod>, <timeoutInMiliseconds>)
  • If users do something on the app (move, click, input), we clear the timeout by using clearTimeout method and then call setTimeout again.

However, this solution is just working fine if the users are on a single tab. If they are using our app on multiple tabs, it should be an issue since they are active on the current tab but inactive on the rest. Then we need to find another solution that allows the active state to sync across multiple tabs.

Implement an idle timer on multiple tabs

Take a look at the diagram first:

Implement idle timer on multiple tabs

There are 3 things that I need to clarify:

  1. localStorage: we need to share the active state across the tabs so we will use it.
  2. Set new expired time flow: when the users interact with our app, we consider they are active and need to re-calculate the new expired time for them. It should be: <current time> + <timeout time>
  3. Interval tracker: We will create an interval to run every amount of time (eg: 1 second) to check the Expired time in localStorage. If the current time is over the expired time, we will handle the timeout action to clear the current session (eg: Auto logout)

Let me translate the diagram to JavaScript point of view.

Idle timer on multiple tabs in JavaScript

As you can see, the actual timeout is in localStorage instead of the application tabs so the timeout will happen for all tabs when we reach the expired time.

I think you are able to understand the concept. Let’s get our hands dirty with the coding implementation.

Step 1: Create user interaction handler

In this post, we will track only 3 events: mouse move, mouse click, and keyboard event.

Create IdleTimer class with our following code. We will have a full demo code at the end of this post so just read the code first.

Explain:

  • Line 9–11, the updateExpiredTime(): We calculate new expired time then store to _expiredTime in localStorage. We have the value of this.timeout from the constructor.
  • Line 13–17, the tracker(): we add the event listeners to track user interaction with mousemove, scroll, and keydown event.
  • Line 5, the binding handler: If you’re not familiar with this syntax, please take a look at this answer to understand. Because the updateExpiredTime() method needs to access this.timeout (line 10) so the .bind(this) will keep the scope in the class scope.

Step 2: Add the interval to track timeout

Now, we need to add the interval to track expired time in localStorage. Let’s update our IdleTimer class as the following code:

Explain:

  • Line 11: At the start point, we need to generate our first expired time.
  • Line 13–18: The interval logic to track every 1000 milliseconds (1 second)
  • Line 14: Get the expiredTime from localStorage. If it doesn’t exist in the storage, then expiredTime is assigned to 0. It’s possible null because 1 browser tab is expired, the storage will be cleared.
  • Line 15–17: To track if the current time is over the expired time.

Step 3: Add the timeout callback

I think you’re still confused after 2 above steps because it’s just a single class. How we expose this class for the others to use? This step will give you the answer. We need to inject a callback from outside of our class. Take a look at the updates:

And this is how we use this class from outside. I’m using React for this demo so you can apply in a similar way.

Create your App.js as below:

I’m assuming you have a basic understanding of React hooks (useEffect, useState) so I’ll just explain the logic instead.

Explain:

  • Line 7–11: We create IdleTimer instance with timeout=10 and the onTimeout callback to update the value of isTimeout
  • Line 15: We just add a simple render here. If the user is inactive in 10 seconds, we will display Timeout text. Otherwise, we display Active . In a real use case, we can render a component instead or even redirect users to the login page.

Step 4: Clean up

We’re almost done with the previous step. Why do we need to clean up?

There are 2 things that we need to clean up in the IdleTimer.

  1. After the timeout is reached, we need to stop the interval or it will keep looping forever.
  2. We also need to remove the listeners for mouse move, mouse click and keyboard input since we don’t need to track these events anymore.

We add the cleanUp method to IdleTimer class like this:

And then we update the interval logic to clean up when reaching the timeout

We also need to refactor App.js for the useEffect hook

1 more step: Improve the user interaction tracker

If you take a look at our tracker(), you will see that we re-calculate the new expired time every time users move their cursor so it’s not really good from a performance point of view. We can improve a little bit by adding the delay as the following diagram:

You can see that we will have 1 new thing: The timeout tracker. For example, when users interact, we create a timeout tracker. If they stop interact for a short period (eg: 300 milliseconds), the timeout track is reached then we store the expired time to localStorage. If they keep moving the cursor in that 300 milliseconds period, we will clear the old timeout tracker and create the new one. Let’s see how we can implement it by the following code:

The last improvement

What if the users close the window and then they open the app again?

We need to check the expired time in the initial state. There are 2 scenarios here.

  1. If they are still in the active time: Our solution can still handle by creating the new expired time. No problem.
  2. If they open the app after the expired time, we need to immediately trigger the onTimeOut instead.

Look at the updates:

Explain:

  • Line 6–10: we check the the initial state if we have the expiredTime value in localStorage, we immediately call onExpired callback and then stop the execution.

We also need to add 1 more line:

As you can see we have the line number 47 to remove the expiredTime from localStorage to make sure that the next initial state (probably users will log in once again) will generate the new expired time.

Then we need to update the App.js:

Why do we have 2 separated callbacks here? You can name whatever you want but the purpose is:

  • onTimeout: The callback will be triggered if the users are in the app and have the idle timeout.
  • onExpired: The callback will be triggered if the users re-open the app after the expired time.

Finally, we’re done for the idle timer across multiple tabs.

Here is the full demo on Codesandbox:

https://codesandbox.io/embed/sleepy-euler-kw4m0?fontsize=14&hidenavigation=1&theme=dark

If you’re using Angular, you can take a look at this demo:

Now it’s your turn, you can try to apply for the other frameworks and make our IdleTimer class to be more reusable by passing more arguments to the constructor.

If you have any trouble or feedback, please share your comment below.

Thanks for your time & enjoy the code!!

JavaScript
Javascript Tips
React
Reactjs
Programming
Recommended from ReadMedium
avatarAnahit Vardevanyan
Design Patterns in React

Introduction

4 min read