React-Router v6: How to skip/replace multiple history entries of authentication flow?

Viewed 120

According to the documentation https://reactrouter.com/docs/en/v6/examples/auth and common sense it is good practice to 'replace' login routes after success authentication.

The use of navigate("...", { replace: true }) to replace the /login route in the history stack so the user doesn't return to the login page when clicking the back button after logging in

Everything is clean if there is only one login route.

Question: what to do if there are multiple routes in authentication flow?

For example: /login/step-one-> /login/step-two -> /login/step-blabla. Number of steps may depend on user settings and/or authentication conditions. it would also be correct to let the user navigate between steps back in the authorization process (for example, choosing a different confirmation method).

Issues:

  • Sample code from the documentation shows how to replace only the last step so history stack will be /login/step-one-> /login/step-two -> /. So back button follows to a meaningless location.
  • It is possible to navigate(-N) and then replace it. But number of steps back is unknown because useLocation doesn't provide state.idx to calculate difference between begin and end of authentication. Underlaying library has getIndexAndLocation method but it doesn't exported in react-router. https://github.com/remix-run/history/blob/3e9dab413f4eda8d6bce565388c5ddb7aeff9f7e/packages/history/index.ts#L370
1 Answers

If there is a multi-step login process (I don't know why'd you make it more difficult to log in) then in this case I'd say using redirects to maintain control over the history stack so the browser's/device's back button goes back to the correct previous page is what you'd want to use. It may be better to think of these as "steps" rather than "pages" that have been navigated to. The multi-step form process should have the UI to handle moving forward/backward through steps while any back navigation buttons (browser or UI) will correctly navigate back to the page prior to starting the stepper flow.

Example:

UI Action History Stack Path Back Location
initial ["/"] "/"
Start login flow PUSH "/login/step-one" ["/", "/login/step-one"] "/login/step-one" "/"
Step 2 REPLACE "/login/step-two" ["/", "/login/step-two"] "/login/step-two" "/"
Step N REPLACE "/login/step-blabla" ["/", "/login/step-blabla"] "/login/step-blabla" "/"
Back to Step 2 REPLACE "/login/step-two" ["/", "/login/step-two"] "/login/step-two" "/"
Back to Step 1 REPLACE "/login/step-one" ["/", "/login/step-one"] "/login/step-one" "/"
Forward to Step 2 REPLACE "/login/step-two" ["/", "/login/step-two"] "/login/step-two" "/"
Forward to Step N REPLACE "/login/step-blabla" ["/", "/login/step-blabla"] "/login/step-blabla" "/"
Complete REPLACE page accessed ["/"] "/" "/"

This requires the multi-step login process to know its steps and current step so it can "navigate" between steps within the current history stack entry. Note that the "back location" is maintained to be the page entry prior to starting the login flow and that at any time the back button/back navigation is issued the app goes back to this page.

An alternative is to not use redirects at all and keep a count of how many pages/steps the user stepped through and issue a manual back navigation that many steps when complete.

Example:

UI Action History Stack Path Back Location Count
initial ["/"] "/" 0
Start login flow PUSH "/login/step-one" ["/", "/login/step-one"] "/login/step-one" "/" 1
Step 2 PUSH "/login/step-two" ["/", "/login/step-one", "/login/step-two"] "/login/step-two" "/login/step-one" 2
Step N PUSH "/login/step-blabla" ["/", "/login/step-one", "/login/step-two", "/login/step-blabla"] "/login/step-blabla" "/login/step-two" N
Back to Step 2 POP (1) ["/", "/login/step-one", "/login/step-two"] "/login/step-two" "/" 2
Back to Step 1 POP (1) ["/", "/login/step-one"] "/login/step-one" "/" 1
Forward to Step 2 PUSH "/login/step-two" ["/", "/login/step-one", "/login/step-two"] "/login/step-two" "/login/step-one" 2
Forward to Step N PUSH "/login/step-blabla" ["/", "/login/step-one", "/login/step-two", "/login/step-blabla"] "/login/step-blabla" "/login/step-two" N
Complete POP (-Count) ["/"] "/"

This also requires the multi-step login process to know its steps and current step count so it can "navigate" between steps so when the flow is complete it can correctly navigate back the correct number of page entries.

Related