Toggling Authentication Providers: Local Storage & HTTP Headers

Our team is introducing a new service for authentication. We’re changing workflows to align with other applications in the client’s ecosystem. In order to make the transition properly, we need to keep the old service around until we’re sure the new authentication infrastructure is ready to go. We also need to give users the ability to choose which service to use when authenticating so they can be sure they’re logging into their desired account. That led the team to explore the idea of toggling authentication providers.

Providing multiple avenues of login is not a new concept. Many applications allow users to log in using various social media applications (i.e. Google, Facebook, etc.). But those components usually just redirect to the social application’s login code. In our case, we need to manage the switch between providers in our backend. We’re consuming the data the same way in the frontend, but we need to tell our backend how to handle it properly. To accomplish this, we decided to add a toggle to our login page. Users can flip the toggle to specify which type of authentication they’d like to use. Below, I’ll describe how we implemented it.

Writing to localStorage

The toggle presents a couple of interesting problems. First, we need to persist the authentication type if the user reloads the page (so they aren’t logged out every time). We couldn’t use our normal client-side state management for this, in our case Redux. So we started to explore storing things in the browser.

localStorage seemed like a perfect spot to store the toggle’s state because of its persistence across browser sessions. This way, if a user closes the application and reopens it, they can stay logged in with their preferred method. We set up our toggle using a React hook.

This code initializes React’s useState hook in our component and sets our default authentication type to Okta:


 const [authProvider, setAuthProvider] = useState(
  "Okta"
 );

Then, in the toggle’s onClick function, we update the value in local storage and in React state (to the opposite value of what was stored in state before the click).


 localStorage.setItem(
  "authType",
  authProvider === "Auth0" ? "Okta" : "Auth0"
 );
 setAuthProvider(
  authProvider === "Auth0" ? "Okta" : "Auth0"
 );

Adding a Custom HTTP Header

Now that we have the user’s chosen authentication type persisted in localStorage, we need to pass it to the backend. Our client and server communicate via HTTP requests, so it makes sense to pass this data as part of that process. We can easily give the backend this information by defining a custom HTTP header on all of our requests. When our server receives a request, it can read the authentication type from the headers and authorize the user to use the correct adapter. Axios makes this super easy, but it’s totally possible to add custom HTTP headers using other methods.

Here, we build an Axios instance that we use for all of our requests.


 axios.create({
  headers: {
    AuthType: localStorage.getItem("authType"),
  },
 });

When we use this instance to send a request, the server can parse the AuthType header and direct the request through the correct authentication code. And that’s it! A simple method to pass browser state, controlled by a client component, to the server.

Beyond Toggling Authentication Providers

Our team used this pattern for toggling authentication providers, but there are plenty of other ways to use it. localStorage is a great place to store any kind of data needed across browser sessions. When that data needs to be sent via a request to the server, HTTP headers are a great candidate.