Getting AzureAD authentication to work smoothly in Flutter apps

Photo by James Harrison on Unsplash

As a former Xamarin developer, I am used to work with AzureAD and the infamous Microsoft Authentication library (MSAL) as the authentication backbone for my apps. However, when me and my team switched to Flutter two years ago and started migrating apps for our customers, we faced several problems getting AzureAD to work together with Flutter apps in a smooth way.

So, here I want to share with you some of the major issues using AzureAD/MSAL in conjunction with Flutter and how we solved them. Since we use Remi Rousselet’s outstanding riverpod for state management, most of the code samples are based on riverpod, but all of this should be easily transferable to any other state management solution.

Also, I heavily recommend using gbwisx’ port of MSAL, which you can find here. It is very well documented and works smoothly together with both the system browser and Microsoft’s Authenticator app on iOS and Android. This article assumes that you have already set up MSAL following the plugin’s documentation on GitHub.

This is neither a deep dive into the inner workings of AzureAD or MSAL, nor a riverpod tutorial. There are many well-curated resources out there that help you getting started, e.g.

I also will not discuss the pros and cons of using AzureAD over Firebase, which is — no doubt — the way to go when creating new apps with Flutter.

We want to tell a user to sign in whenever needed — and handle any changes to the authentication state in the UI. In this example, we will build something like this:

As long as no user is signed in, there is a bottom sheet indicating that a sign in is needed. No request is performed as long as nobody is signed in.
Once the user signs in, the authentication process begins (here, I did not have Microsoft’s Authenticator app installed, so the authentication was handled in a browser window by MSAL)
After authentication, the current user is shown and the bottom sheet is gone. Requests will automatically be authenticated from now on.

First of all, we need to enable our app to sign in and sign out users. This is quite straightforward. The _AuthenticationService below handles the authentication logic (signing in, signing out, getting a token, handling the Microsoft Authenticator logic, etc.) and there is merely any difference to the samples provided in msal_mobile’s documentation.

As the authentication logic used by msal_mobile lacks a bit of flexibility, we decided to go with a litte initialization hack that keeps track of the initialization state of the MSAL instance. When initializing, msal_mobile reads a configuration file that contains information about the app’s signature, the AzureAD instance to authenticate against and the integration of Microsoft’s Authenticator app.

So, we simply follow the basic principles when using MSAL here. Finally, we provide the service as a trackable dependency using riverpod.

So our authentication service can now handle the lower-level authentication logic — great! But, still the UI does not get notified about any changes at all.

  • What if the user signs out?
  • What is the current state? Is a user currently signed in?
  • Can we make a request without running into 401 codes?
  • Should the app show a banner indicating that the user needs to sign in?

We need to keep track of the authentication state, which is exactly what riverpod is made for. Below, we provide a AuthenticationNorifier to our app that encapsulates the logic handled in our _AuthenticationService. Whenever the authentication state changes, each listener is being notified and can react accordingly. For the sake of simplicity, in this sample we only use a boolean flag indicating whether any user is signed in or nor. One could easily expand the states, e.g. by indicating that there is a user currently signed in (in MSAL this means that there is a last-known UserAccount), but there is no valid token available.

This one had us badly scratching our heads at first. If we actually perform a request, how can we make sure that the request is authenticated correctly? Before we came across interceptors in Dio, we had a pretty bad-shaped singleton implementation of our request handler, calling into our _AuthenticationService directly before a request was performed.

Even though the solution bwloe looks quite easy, we needed some time to get to this, as we did not use provider references (ref) in the beginning:

One great thing about riverpod’s provider reference mechanism is that it allows listening to every state change happening in our _AuthenticationService easily.

The interceptor now authenticates each and every request and makes sure that there is no request being left un-authenticated (which would finally lead to 401 errors). For the sake of simplicity, I skipped the interceptor that handles any 401 error properly in the gist.

So, how can we tell the user that he needs to sign in? As our authentication state is now properly handled and published to subscribers, we only need to listen to changes in the UI.

For this example, we make use of hooks_riverpod in order to use the provided authenticationProvider. The scaffold shown below is state-aware to any changes happening to the authentication state. Here, we simply show a bottom sheet telling the user to sign in if needed:

And that’s it! We managed to create a wrapper around msal_mobile that notifies the UI about any changes to the authentication state in the app. Furthermore, we created an interceptor for Dio to make sure that every request is authenticated properly. Finally, we notified the user about a missing sign in.

If you have questions on how to manage authentication state with MSAL and riverpod, just head over to my GitHub profile where you can find links to my social media.

Happy coding and thank you for coming around! 🎉