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.
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.
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.
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.
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.
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.
window.postMessage call]. 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.
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 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.