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:
react-idle-timer
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 movedkeydown
– Fires when a key is pressedwheel
– Fires when the wheel of a pointing device is rotatedmousedown
– Fires at an element when a button on a pointing device is pressedtouchstart
– Fires when one or more touch points are placed on the touch surfacetouchmove
– Fires when one or more touch points are moved along the touch surfacevisibilitychange
– Fires at the document when the contents of its tab have become visible or have been hiddenMSPointerDown
– Fires when a pointer becomes activeMSPointerMove
– Fires when a pointer changes coordinatesThere 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.
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> }
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 millisecondspromptTimeout
– Set the timeout for onPrompt
to be calledonPrompt
– Displays a confirmation prompt before calling onIdle
onIdle
– Called when user is idle[debounce](https://blog.logrocket.com/how-and-when-to-debounce-or-throttle-in-react/)
Then we export the isIdle
state variable, the setIdle
state action, and the idleTimer
object.
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:
The video below demonstrates app behavior with an idle timer implemented.
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!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]