How do you share authentication in micro-frontends
Tags: frontend, microfrontend, auth
Published: 2020-08-31 09:34:30

Lately the internet has been abuzz about micro-frontends. Micro-frontends are a great pattern for enabling teams to deliver customer facing value quickly and independently. However like any choice in software development the benefits also come with some cost. By breaking up the application sharing state becomes harder, and that includes sharing authentication. In this post I'll have a look at a way to have different components know if a user is authenticated.

First a super fast overview of what a micro-frontend is.

# Micro-frontends

With a traditional application the monolith frontend dominated, even as back end services were moving to micro-service architectures. This architecture presents a single application to the world which consumes one or more back end services.

![A diagram representing a user interacting with a monolith frontend aggregating multiple back end services](https://dev-to-uploads.s3.amazonaws.com/i/4zx66na0rjucznp5excj.png)

Micro-frontends are an approach to front end architecture where the client facing Single Page Application is broken down into multiple code bases rather than being one large code base. From the users perspective the multiple applications are presented as a single cohesive experience even though they are moving between
 multiple code bases.

This has a range of benefits, including allowing teams to work on a vertical slice of the application rather than having one team own the entire frontend or having multiple teams contributing to one code base. Micro-frontends are typically combined with micro-service backend architectures and allows teams to scale and make decisions independently. Because each micro-frontend is a separate code base they are not required to share the same technology stack or front end architecture. One may be a JAM Stack SPA written in Vue.js, while another may be a server rendered application written in React and Next.js while yet another may be a Ruby on Rails application. The underlying technology doesn't matter as long as a user can move between them seamlessly. There are multiple ways of knitting together these frontends into a single user facing experience. The simplest of them is to use a reverse proxy to direct the traffic to different applications based on the path that a users is accessing.

![A diagram representing a user interacting with micro-frontends hidden behind a reverse proxy for path based routing](https://dev-to-uploads.s3.amazonaws.com/i/753oci59lngmp3fuoygd.png)

# Authentication

## Single frontend

In a monolith frontend application the front end takes the users credentials and sends them to a server that is able to validate the credentials and returns an authentication token if they're correct. The front end is then able to use this authentication to prove it's identity to the APIs it's consuming.

## Micro-frontend

When moving to a micro-frontend architecture, with each of the frontends being their own application there is no shared state that can be used to store authentication tokens once the user has logged into the first application. Our goal is to have each of these application acting as though they are one application to the user so we don't want each of the front ends to require that the user enters when they move between the frontends.

## Sharing authentication

The way that this can be overcome is by using the Open ID Connect protocol and introducing an application that is responsible for handling the authentication running on a separate domain. If your app is running on `my.app.com` then this authentication application might be hosted at `id.my.app.com`. When a frontend wants to authenticate a user it redirects the user out to this application. The first time the user arrives on this page they are presented with a credential entry screen and go through a standard authentication process. When the process is completed they are redirected back to the original location with an access token, identity token and optional refresh token in the query. Before this redirect though the authentication application bakes a cookie that is stored on the domain. Now when a subsequent front end redirects the user back the authentication application checks this cookie and uses it to assert that the user has previously proved their identity and the user is redirected back without being forced to prove their identity a 2nd time.

![Sequence diagram showing the redirection flow for shared authentication](https://dev-to-uploads.s3.amazonaws.com/i/ewj3h81ue81tea1of4do.png)

## Silent authentication

Sharing authentication through redirecting users to a central location solves the problem of being able to share the one authentication session between applications without forcing the user to log in. Unfortunately it can be a jolting experience for the users. Redirects aren't free even if the user is on a fast internet connection they are going to notice the constant redirecting. The solution to this is to do the authentication in a way that is hidden from the user. One method of approaching this is to perform the authentication exchange inside a hidden iframe. In this solution the application uses JavaScript to add a 1 pixel iframe into the DOM that handles the authentication experience and passes the resulting tokens back using a [`window.postMessage` call](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)]. If the silent authentication fails the message instead informs the application that a login is required and the user can be redirected to provide their credentials.

# Making it easier

If you're like me that all sounds too complicated to implement myself. I'm bound to muck it up somewhere, fortunately if you're using Auth0 the [SPA SDK](https://auth0.com/docs/libraries/auth0-spa-js) take care of everything for you. It provides options for authenticating your users using silent authentication, redirecting them to a hosted login or using a popup window so that your micro frontend can maintain its current state.