How to make an idle timer for your React app

How to make an idle timer for your React app

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

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.

Our login page
Our homepage when we're logged in
Our homepage when we’re logged in

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:

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 C*lose* 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 —
.


Source link