frontend icon indicating copy to clipboard operation
frontend copied to clipboard

Bad behaviour on session expiration

Open angelsl opened this issue 3 years ago • 0 comments

Background

Originally, when any backend request returned a 401 (Unauthorized) or 403 (Forbidden), the frontend would redirect the user to the login screen. This happens most often when the user's refresh token expires (~1 week after they log in). Of course, if the failing request was e.g. a request to save the user's work in an assessment, this would be bad, so certain endpoints were marked as "no auto logout", and instead of redirecting to the login screen, it would just show a message telling the user to save their work and log in again.

This should not have been done this way, but it was what we had from the start (at least since I got involved), and it was sufficient as no other requests were made in the assessment workspace anyway.

I believe when achievements(?) and other features were added, other requests started being sent in the background even in the assessment workspace, and that caused some users to lose their work due to the auto-logout caused by those background requests returning a 401/403.

Last semester as a quick workaround to avoid these issues, I removed the auto-logout entirely in https://github.com/source-academy/frontend/commit/691baa22b7adee268ada8499ea1a373cd3e1085d. However, this means that upon session expiration, the user gets a bunch of confusing errors and has to manually log out and in again.

Suggested fix

Instead of disabling auto-logout per-route, it should be done based on the currently active page (and perhaps the state). In fact, we can just make this the "confirm page change" flag and centralise the handling of that instead of the various methods used around the codebase currently (react-router's Prompt component, etc).

Have a global counter that can be accessed from the backend request methods (I suppose it will have to be in the Redux store...).

Then, write a hook like this:

function useConfirmPageChange(confirm) {
  useEffect(() => {
    if (!confirm) { return; }
    // increment the confirm page change flag counter
    dispatch(actions.setConfirmPageChange());
    return () => {
      // when this hook is disposed, decrement the confirm page change flag counter
      // since the dependencies array is empty below, this happens only when the component is unmounted
      // or `confirm` changes from true to false
      dispatch(actions.clearConfirmPageChange());
    };
  }, [confirm]);
}

In the backend request method, check the counter and if it is nonzero, then don't redirect to login if the request 401/403s.

In one of the root components, we can add some handling to block and confirm a route change (e.g. by rendering the react-router Prompt component) if the counter is nonzero, and replace the adhoc "unsaved changes" handling in the grading workspace, assessment workspace etc.

angelsl avatar Feb 15 '22 15:02 angelsl