Matt Angelosanto
Posted on March 9, 2023
Written by Ivy Walobwa✏️
An idle timer is one way to add an additional layer of security to your web application. An idle timer is used to sign out a user after checking whether they’ve been inactive for a specified duration.
When building websites that contain highly confidential user information, the platform’s security is a major concern. As a developer, you need to guard the end user against intruders. Implementing an idle session timeout to sign a user out of their current session is one way to enhance the platform’s security.
For example, with applications that make API calls every 30 seconds, it is necessary to implement an idle timeout to improve the app's performance. This logs the user out when idle and prevents unnecessary backend requests.
In this article, we’ll learn how to implement an idle timeout in your React application. We’ll use the react-idle-timer
package to detect and respond to the user’s idleness.
Jump ahead:
- Events for idle detection in
react-idle-timer
- Getting started
- Creating a custom idle detection Hook
- Using the idle detection custom Hook
Events for idle detection in react-idle-timer
The DOM API provides mouse and keyboard events that can be used for idle detection. The react-idle-timer
package makes use of the following events to detect user activity:
-
mousemove
– Fires when a pointing device is moved -
keydown
– Fires when a key is pressed -
wheel
– Fires when the wheel of a pointing device is rotated -
mousedown
– Fires at an element when a button on a pointing device is pressed -
touchstart
– Fires when one or more touch points are placed on the touch surface -
touchmove
– Fires when one or more touch points are moved along the touch surface -
visibilitychange
– Fires at the document when the contents of its tab have become visible or have been hidden -
MSPointerDown
– Fires when a pointer becomes active -
MSPointerMove
– Fires when a pointer changes coordinates
There are also two deprecated events, DOMMouseScroll
and mousewheel
, which we won‘t focus on in this post.
The react-idle-timer
package binds all of these events to a DOM element by adding an event listener for each. User idleness is then toggled based on the last time the bound events were triggered.
Getting started
In your terminal, create a new React application and start the development server using the commands below:
npx create-react-app idle-timer-react
cd idle-timer-react
yarn start
Then, open the React application in your favorite code editor. You will create a simple web application with a HomePage
and a Login
page, as shown below. The App.js
file displays the homepage and login page based on the authentication status.
import Login from "./components/Login";
import 'bootstrap/dist/css/bootstrap.min.css';
import { useState } from "react"
import AuthContext from "./context/AuthContext"
import NavigationBar from './components/NavigationBar'
import HomePage from './components/Homepage'
const App = () => {
const [authstatus, setauthstatus] = useState(false);
const login = () => {
setauthstatus(true);
};
const logout = () => {
setauthstatus(false);
};
return (
<AuthContext.Provider value={{ status: authstatus, login: login, logout: logout }}>
{authstatus ? <>
<NavigationBar />
<HomePage />
</> : <Login />}
</AuthContext.Provider>
)
}
export default App;
The HomePage
will contain a displayed text and a modal that will only display when the user is idle.
const HomePage = () => {
const [openModal, setOpenModal] = useState(false)
const { logout } = useContext(AuthContext);
const handleIdle = () => {
setOpenModal(true);
}
const stay = () => {
setOpenModal(false)
}
const handleLogout = () => {
logout()
setOpenModal(false)
}
return <Container className="mt-4">
<Row>
<Col></Col>
<Col>You are now logged in </Col>
<Col></Col>
</Row>
<Modal show={openModal} onHide={stay}>
<Modal.Header closeButton>
<Modal.Title>Your session is about to expire</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
Your session is about to expire. You'll be automatically signed out.
</p>
<p>
Do you want to stay signed in?
</p>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleLogout}>
Sign out now
</Button>
<Button variant="primary" onClick={stay}>
Stay signed in
</Button>
</Modal.Footer>
</Modal>
</Container>
}
export default HomePage;
The Login
signs the user into the application when the login form is submitted.
const Login = () => {
const { login } = useContext(AuthContext);
const handleLogin = async e => {
e.preventDefault()
login();
};
return <Container className="mt-5">
<h1> Please Login</h1>
<form onSubmit={handleLogin}>
<p>Password</p>
<input type="password" />
<div>
<button type="submit">
Login
</button>
</div>
</form>
</Container>
}
Creating a custom idle detection Hook
We can create a custom Hook in our application to implement the react-idle-timer
package to detect user inactivity. First, install the package using the following command:
yarn add react-idle-timer
Then, create a useIdleTimeout.js
file, which we’ll use to contain the custom Hook for idle detection. You can learn more about creating custom Hooks in this article.
Add the code snippet below to the new file:
import { useContext, useState } from "react"
import { useIdleTimer } from "react-idle-timer"
import AuthContext from "../context/AuthContext";
/**
* @param onIdle - function to notify user when idle timeout is close
* @param idleTime - number of seconds to wait before user is logged out
*/
const useIdleTimeout = ({ onIdle, idleTime = 1 }) => {
const idleTimeout = 1000 * idleTime;
const [isIdle, setIdle] = useState(false)
const { logout } = useContext(AuthContext);
const handleIdle = () => {
setIdle(true)
logout()
}
const idleTimer = useIdleTimer({
timeout: idleTimeout,
promptTimeout: idleTimeout / 2,
onPrompt: onIdle,
onIdle: handleIdle,
debounce: 500
})
return {
isIdle,
setIdle,
idleTimer
}
}
export default useIdleTimeout;
This code contains an implementation of the useIdleTimer
function from the react-idle-timer
package. The useIdleTimeout
Hook expects to call an onIdle
function when a user is idle, and idleTime
, which indicates the number of seconds to wait before a user is marked as idle.
We store the idle state of a user in the isIdle
state variable. The useIdleTimer
Hook from the package is called with the following properties:
-
timeout
– Set the activity timeout, in milliseconds -
promptTimeout
– Set the timeout foronPrompt
to be called -
onPrompt
– Displays a confirmation prompt before callingonIdle
-
onIdle
– Called when user is idle -
debounce
Then we export the isIdle
state variable, the setIdle
state action, and the idleTimer
object.
Using the idle detection custom Hook
We can now use the custom idle timer Hook in our application. Update the HomePage
file as shown:
const HomePage = () => {
const [openModal, setOpenModal] = useState(false)
const { logout } = useContext(AuthContext);
const handleIdle = () => {
setOpenModal(true);
}
const {idleTimer} = useIdle({ onIdle: handleIdle, idleTime: 5 })
const stay = () => {
setOpenModal(false)
idleTimer.reset()
}
const handleLogout = () => {
logout()
setOpenModal(false)
}
return ...
}
In this code, we create an instance of the useIdle
Hook, which in turn automatically starts the idle timer for us. The idle timer resets when the Stay signed in button is clicked.
When a user stays idle for half of the specified time, we’ll display a prompt. If the user does not interact with the prompt, then they’ll be logged out automatically. However, when they interact with the modal, their interactions produce the following results:
- When the user clicks the Close button, the idle timer is reset and the user stays logged in
- When the user clicks Stay signed in, the idle timer is reset and the user stays logged in
- When the user clicks Sign out now, the user is logged out and the idle timer is destroyed
The video below demonstrates app behavior with an idle timer implemented.
Conclusion
Implementing an idle timer can improve the security of your web application. When adding an idle timer, it is important to carefully consider the duration of the timeout based on the user information’s level of risk. It is equally important to provide appropriate timeout notifications to the user to avoid disrupting their workflow.
In this tutorial, we implemented an idle timer using the react-idle-timer
package, which handles the binding and unbinding of keyboard and mouse events for us. We made use of the exposed properties and methods to add an idle timer to our React application.
All of the code in this article is available on GitHub. I hope you enjoyed this tutorial!
Cut through the noise of traditional React error reporting with LogRocket
LogRocket is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications.
LogRocket automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.
Focus on the React bugs that matter — try LogRocket today.
Posted on March 9, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024