Saving and using custom data before and after redirecting users to external services with Remix

Photo by Carlos Muza on Unsplash

Saving and using custom data before and after redirecting users to external services with Remix

If you've read my other two articles on how to create toast notifications and confetti rain in Remix you would've noticed a common pattern I used among them, and that pattern is flash storage.

In today's article, I will show you a little trick on how you can store a custom flash session before you send a user to a third-party service without passing the info along and then parsing it on user return.

For this article, I will use Auth0 Universal login using remix-auth as an example and a redirectTo param that would redirect the user back to where he was after he logs in, but you can store whatever you need into the session and consume it later on.

So the approach is the same as in this article:

https://alemtuzlak.hashnode.dev/handling-toasts-in-remix

If you haven't read it I recommend you skim over the flash storage part so you understand what we're doing!

First of all, let's assume you have a route "login.tsx", and if the user is inactive for a while you log him out and send him to that route. On that route we naturally want to send the user to Auth0 for him to log in. Let's also asume he was on a custom route, let's say "/dasbhoard", so what we want to do is send the user to Auth0, and when he is back and logged in we want him to be back on the dashboard as if nothing happened.

Implementing the redirectTo behavior is out of scope of this article but let's assume you get it from the url as a search parameter. Well, let's first implement what we need in the flash-session.server.ts file:

// Schema to validate the flash session storage
const flashSessionValuesSchema = z.object({ 
  // validation schema from above
  toast: toastMessageSchema.optional()
  // we add a redirectTo (this is the part where it can be whatever you need)
  redirectTo: z.string().optional()
});

Alright, so now all we have to do is the following in our "login.tsx":

export const loader ({ request }: LoaderArgs) => {
  // We generate the URL object to easily extract search params
  const url = new URL(request.url);
  // We get the redirectTo
  const redirectTo = url.searchParams.get("redirectTo");
  // We do not consume the headers from the flash so it is kept in flash storage until used
  const { flash } = await getFlashSession(request);
  // The url contains no redirect path or the redirectTo has already been stored, we directly redirect to the auth0 login page
  if (!redirectTo || flash?.redirectTo) {
    return authenticator.authenticate("auth0", newRequest, {
      failureRedirect: "/login"
    });
  }  
  // We redirect back to here to store the redirect path in the flash session
  return redirectWithFlash(PATH.LOGIN, { redirectTo }, request);
}

So what are we doing here? Well, it's very simple, if the user lands on login with a redirectTo in the search params we redirect to login again and store the info in the flash session, and then on the next loader call we will have it in the flash session and we will redirect the user to the Auth0 universal login, pretty simple!

And the final piece of the puzzle is to actually use the flash session, Let's say the user is back on a different route in /auth/callback, well all we do there is:

export const loader = ({ request }) => {
  const { flash } = await getFlashSession(request);
  // handle the authenticator part and store the tokens etc.
  const redirectTo = flash?.redirectTo;
  return redirect(redirectTo ?? "/default-path");
}

And that's it! We redirect the user to where he was and the flash session is removed by our root.tsx loader and we're done!

Thank you!

If you've reached the end you're a champ! I hope you liked my article.

If you wish to support me follow me on Twitter here:

twitter.com/AlemTuzlak59192

or if you want to follow my work you can do so on GitHub:

github.com/AlemTuzlak

And you can also sign up for the newsletter to get notified whenever I publish something new!