Table of contents
BACKGROUND
Hi there,
Sometimes an application needs some intervention after a certain period of user inactivity. For example, consider a financial application where you have user details and financial status in display, the user might need to be logged out to protect sensitive data after some time (based on preference) of user inactivity. This is a security measure which will prevent another user (or you) from accessing the application without having to log in again.
Here's a guide on how to detect user inactivity and take necessary action whichsoever. I am using Next.js but the same principles would work with Create React App and React Router Dom.
BODY: HOW TO DETERMINE AN INACTIVE USER
A user is only active when there is an interaction, which can range from clicks, mouse (cursor) moves, scrolls and key presses (typing).
Go to the root component of your app which in my case is my App.js file.
- Create a function to set the expiry time and store it in the local storage. This gives you the privilege to grab it later.
Note: Date.now() is the current time
300,000 is equivalent to 5 minutes. This essentially means that the user only has up to five minutes of inactivity before an intervention.
- Create another function which will get the expiry time from the local storage and run a check. You are going to perform an intervention when the expiry time is less than the current time which means that the user has been inactive for the duration of the expiry time (5 minutes).
If the expiry time is less than the current time represented by Date.now(), run the intervention. For example, log out the user.
More practically, assuming the current time is 5:00pm, this means that the expiry time at this current time would be 5:05pm. If the user is active, both the current time and the expiry time would keep increasing simultaneously which means that in the next two minutes, the current time would be 5:02pm while the expiry time would be 5:07pm.
Recall: The expiry time is the current time with an addition of five minutes.
The expiry time would only be less than the current time if the current time keeps increasing while the expiry time remains constant showing that the user is inactive.
- Ensure that the setExpiryTime function created earlier runs and updates as you listen to various events which indicates user activity.
Hence, create a useEffect hook with an empty dependency array which means that the callback function is called once the page renders.
Then call the setExpiryTime function to set an initial expiry time and then call the function again for every event you listen to.
These four events basically cover user activity as the user can only click, type, scroll or move the cursor. In cases of brainstorming, probably a continuous stare at the screen, it takes only five minutes before the application reminds you how much time you have been away.
- It is important to clean up by removing the event listeners from the window to prevent performance issues. So return a function that does that in the useEffect hook. The useEffect hook should then look like this;
- Ultimately, create another useEffect hook which would run a setInterval function to check for inactivity after a certain defined period of time and also return a clearInterval function to clear the interval on page unmount.
This runs the checkForInactivity function every ten seconds (can change based on preference) and performs the action when the condition in it is met. It then clears the interval on return.
- As an extra, it becomes imperative to set measures which guarantees good user experience. In this instance, upon logging the user out and returning the user to the sign up page to be re-authorised, it is needful to stop the checkForInactivity function from running. This implies that you only check for inactivity when the user is signed in. When the user is not signed in, there is no reason to check for inactivity or perform any security action. Hence, modify the useEffect hook by running a path check and updating the dependency array.
You can also update the checkForInactivity function with the condition just as below;
Here is the whole code block. Thanks for staying through.
//ensure to import useState
const [isLoggedIn, setIsLoggedIn] = useState(true)
// function to set expiry time
const setExpiryTime = () => {
// set expiry time to 5 minutes from now
const expiryTime = Date.now() + 300000;
// set expiry time in localStorage
localStorage.setItem("expiryTime", expiryTime);
};
// function to check inactivity and intervene
const checkForInactivity = () => {
// Get expiry time from local storage
const expiryTime = localStorage.getItem("expiryTime");
// if expiry time is earlier than now, log out the user
if (router.asPath
!== '/sign-in' && expireTime < Date.now()) {
alert("Session has expired. Please sign in again");
router.push("/sign-in");
}
};
// set and update expiry time on any user activity
useEffect(() => {
// set initial expiry time
setExpireTime();
// set event listeners
window.addEventListener("click", updateExpireTime);
window.addEventListener("keypress", updateExpireTime);
window.addEventListener("scroll", updateExpireTime);
window.addEventListener("mousemove", updateExpireTime);
// clean up
return () => {
window.removeEventListener("click", updateExpireTime);
window.removeEventListener("keypress", updateExpireTime);
window.removeEventListener("scroll", updateExpireTime);
window.removeEventListener("mousemove", updateExpireTime);
};
}, []);
// useEffect to set interval to check for inactivity
useEffect(() => {
// check for inactivity every ten seconds
if (router.asPath !== '/sign-in') {
const interval = setInterval(() => {
checkForInactivity();
}, 10000)
// clear interval on unmount
return () => {
clearInterval(interval)
};
}
}, [checkForInactivity])
CONCLUSION
I hope this article gives you an exhaustive explanation on how user inactivity can be detected and handled giving the user a good experience without compromising data security.
Trust you had a nice read?
Please share your thoughts and opinions in the comments section below.