skip to Main Content

I wanted to refresh the token every 1 hour ONLY if there is a user activity.
Otherwise just remove the token.

Currently, my code below does call the refresh api every 1 hour regardless whether there is user activity or not.

User activity is any movement on your keyboard or mouse.

const App = () => {
  const refreshTokenInterval = () => {
    try {
      const isLoggedIn = useAuthStore.getState().isLoggedIn;
      if (isLoggedIn) {
        AuthenticationService.refresh(null, (response) =>
          CookieService.set(activeAccount, response.data)
        );
      }
    } catch (error) {
      console.log(error);
    } finally {
      setTimeout(refreshTokenInterval, 1000 * 60 * 60);
    }
  };

  useEffect(() => {
    refreshTokenInterval();
  }, []);

  return null;
};

export default App;

4

Answers


  1. This will refresh your token once every time user is inactive for 1 hour if my define of your user activity is right

    const [isInActive, setIsInActive] = useState(false);
    
    useEffect(() => {
      activityWatcher();
      return () => {
        document.removeEventListener();
      };
    }, [activityWatcher]);
    
    useEffect(() => {
      if (isInActive) {
        refreshTokenInterval();
        setIsInActive(false);
      }
    }, [isInActive]);
    
    const activityWatcher = useCallback(() => {
      var secondsSinceLastActivity = 0;
    
      var maxInactivity = 3600;
    
      setInterval(function () {
        secondsSinceLastActivity++;
        if (secondsSinceLastActivity > maxInactivity) {
          setIsInactive(true);
          secondsSinceLastActivity = 0;
        }
      }, 1000);
    
      function activity() {
        secondsSinceLastActivity = 0;
      }
    
      var activityEvents = [
        "mousedown",
        "mousemove",
        "keydown",
        "scroll",
        "touchstart",
      ];
    
      activityEvents.forEach(function (eventName) {
        document.addEventListener(eventName, activity, true);
      });
    }, []);
    
    Login or Signup to reply.
  2. You could try out the below solution

      import { useIdleTimer } from "react-idle-timer";
    
      const FIVE_MINS = 5 * 60 * 1000;
      const GENERAL_DEBOUNCE_TIME = 500;
    
       /**
       * SET USER IDEAL TIME WITH DEBOUNCE
       */
      useIdleTimer({
        timeout: FIVE_MINS, // time in millisecond
        onIdle: handleOnUserIdle,
        debounce: GENERAL_DEBOUNCE_TIME, // time in millisecond
      });
    

    Above code you could add to Parent component. It will track the user activity in case user was not active for more than certain time it will trigger the onIdle function. Where you can add your logic related to refresh token

    NPM – https://www.npmjs.com/package/react-idle-timer?activeTab=readme

    Login or Signup to reply.
  3. you can use useEffect in setTimeout function and time set 1 hour

    Login or Signup to reply.
  4. I’ve abstracted the logic into a hook. The basic logic is based on a running interval that calls the refreshTokenInterval handler once every hour (or any interval you need), and event listeners that detect if there was any activity at all during the previous interval’s duration. If there was activity the the refreshTokenInterval completes the token refresh logic, otherwise if there was no activity refreshTokenInterval kills the running interval and clears the activity event listeners.

    Code:

    const INTERVAL_TIME = 1000 * 60 * 60;
    
    const events = [
      "mousedown",
      "mousemove",
      "wheel",
      "keydown",
      "touchstart",
      "scroll"
      // ... add other events here ...
    ];
    
    const addListeners = (events, cb) => {
      events.forEach((event) =>
        window.addEventListener(event, cb, { passive: true })
      );
    
      return () => {
        events.forEach((event) =>
          window.removeEventListener(event, cb, { passive: true })
        );
      };
    };
    
    const useRefreshTokenInterval = (activeAccount, interval = INTERVAL_TIME) => {
      const intervalRef = React.useRef();
      const unlistenRef = React.useRef();
      const wasActiveRef = React.useRef(false);
    
      React.useEffect(() => {
        const refreshTokenInterval = (initial) => {
          if (!initial && !wasActiveRef.current) {
            // Inactive, clearing interval, not refreshing token
            CookieService.remove(activeAccount);
            clearInterval(intervalRef.current);
            if (unlistenRef.current) {
              unlistenRef.current();
            }
            return;
          }
          try {
            const isLoggedIn = useAuthStore.getState().isLoggedIn;
            if (isLoggedIn) {
              // Attempting token refresh
              AuthenticationService.refresh(null, (response) =>
                CookieService.set(activeAccount, response.data)
              );
            }
          } catch (error) {
            console.log(error);
          } finally {
            // Reset activity for next interval
            wasActiveRef.current = false;
          }
        };
    
        refreshTokenInterval(true); // <-- initial call
    
        // Setup token refresh interval
        intervalRef.current = setInterval(refreshTokenInterval, interval);
    
        // Add activity event listeners
        unlistenRef.current = addListeners(events, () => {
          // There was some activity
          wasActiveRef.current = true;
        });
    
        // Return cleanup function to clear any running interval timer
        // and unsubscribes event listeners
        return () => {
          clearInterval(intervalRef.current);
          if (unlistenRef.current) {
            unlistenRef.current();
          }
        };
      }, [activeAccount, interval]);
    };
    

    Usage:

    useRefreshTokenInterval("account"); // <-- I've no idea what activeAccount is 🤷🏻‍♂️
    

    In this example I extracted activeAccount as an external dependency, so this value may need to be memoized in order to provide it as a stable reference since it is referenced in a useEffect hook’s dependency array.

    Demo

    Here’s a demo using a 10 second token refresh/activity interval.

    Edit handle-user-inactivity-and-logout-in-react

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search