Skip to main content

Remix Authentication Flow

Overview

The authentication flow in our Remix application involves several key steps and components. This document outlines the process, focusing on the login route, session state handling, returnTo parameter, and the callback URL.

Login Route

The login route calls the resource API (auth-resource) from the web-authentication class via a call from a Redux epic. The purpose of this API is to set the session state and the returnTo URL before the login happens.

Session State

While authenticating using Auth0, the state parameter is received and returned to us in the callback URL. We validate the response to ensure it has the correct state parameter to prevent response hijacking or modification. The RemixAuth0Strategy sets the session state in session storage, which is then compared during the Proof Key for Code Exchange (PKCE) process. Example Code:

const session = await sessionStorage.getSession(request.headers.get('Cookie'));
const state = v4(); // Generate a new state value
await session.set(SESSION_STATE_KEY, state); // Set the state in session storage

ReturnTo Parameter

The returnTo parameter is used for redirection after a successful login. For instance, if you were at a route and the session expired, or you visited the page after some time and the session was no longer valid, it will redirect you to the login page with the returnTo parameter set as a query parameter. This parameter contains the previous route, ensuring the user is redirected to their intended destination after login.

const returnToCookie = await getReturnToCookie();
const sessionStorage = await getSessionStorage({ request, context });
const session = await sessionStorage.getSession(request.headers.get('Cookie'));
const state = v4(); // Generate a new state value
await session.set(SESSION_STATE_KEY, state); // Set the state in session storage
const headers = [
['Set-Cookie', await sessionStorage.commitSession(session)], // Commit the session
['Set-Cookie', await returnToCookie.serialize(returnToPath)], // Set the returnTo cookie
];
return json(
{ state },
{ headers },
);

Callback URL

The callback URL is executed when the response comes back from Auth0. Here, we call the authenticate method of the RemixAuth strategy, which will validate the code received in the callback URL and exchange it for the idToken, accessToken, and refreshToken. These tokens are saved in our session storage. Additionally, if the returnTo cookie is set, we retrieve it and redirect to the route it contains.

const session = await sessionStorage.getSession(request.headers.get('Cookie'));
logger.debug('Session fetched.');

session.set(SESSION_KEY, result); // Set authentication result in session
session.set(SESSION_STRATEGY_KEY, 'auth0');
logger.debug('Session updated with authentication result.');

context.store.dispatch(
setUserAccountDetails({ id: result.userId, auth0UserId: result.auth0UserId, profile: result.profile }),
);
logger.debug('User account details set in context store.');

let redirectPath = '';
if (!result.userId) {
logger.warn('User ID not found, redirecting to VerifyUser.');
redirectPath = Auth0Routes.VerifyUser;
} else {
redirectPath = returnTo;
logger.debug(`User authenticated, redirecting to: ${returnTo}`);
}

throw redirect(redirectPath, {
headers: [['Set-Cookie', await sessionStorage.commitSession(session)]],
});