How to set up SSO authentication and RBAC with Azure AD in a React web app: a simple developer’s guide.

Alexei Ivanov
Sopra Steria Norge
Published in
10 min readDec 2, 2021

Introduction

Recently I was working on a project involving a typescript based React web app. I was assigned a task for setting up SSO authentication and authorization with Azure AD. Since it was my first time, I had to go on the Internet to find out how to do it. I was perplexed by the fact that there was literally no documentation that described the process from end to end. The information was scattered and only bits and pieces popped up here and there, and there was no apparent connection between them. This is the reason I started writing this article, so hopefully, it will help someone out there who happens to stumble across a similar task.

First off, I decided to go with MSAL (Microsoft Authentication Library), since it had a fair amount of documentation available, with example code and quite a good amount of detail, though there was no typescript version available at the time (strange as it is an MS invention if you will). Nonetheless, I figured it would be the easiest approach and save me some time and headache to get it integrated.

I started by making some configuration adjustments in my Azure AD, and surprisingly this part was the easiest as it had so much documentation available on how to set things up that I really have to hand it to Microsoft on this one. I will describe this process in bullet points only and simply link to the Microsoft documentation as I would basically be copy-pasting all the way otherwise. Needless to say, you will probably discover that by yourself as you go along.

Prerequisites

This guide assumes that you, or your organization, have an active Azure subscription with Azure AD, and at least one active account (user). Also, it is assumed that your organization uses Azure AD SSO authentication and that your account has the necessary access to Azure AD resources. Furthermore, you will need some sort of a React typescript application with some parts that you wish to protect with your organization’s SSO. The sample application used in this guide utilizes a RESTful API backend service, so some assumptions are made with that regard also.

Configuring Azure AD

Let us begin with logging into the Azure portal at https://portal.azure.com/. You will be prompted with the same SSO flow that we are trying to achieve here. The portal has a simple UI that is pretty intuitive to use, though some help on the way will come in handy. So, if it is unfamiliar territory, you can check out Microsoft’s official documentation. Here is the list of configuration steps that you need to take:

· First you will need to register an application. This is so that all other resources can be logically associated with your React app. Your redirect URI can be something like http://localhost:3000/your-protected-api-endpoint, to begin with. You can modify all this stuff later on under the Authentication tab in your application. Here is what my redirect URI configuration looks like (note that I have one for development, and one for production — and yes, they can coexist without a problem).

Now would be a good time to select tokens that you would like to be issued if you have not done so already:

Also, configure which organizations shall have access to your application. I have selected only my organization to be eligible (single tenant). This will either narrow or broaden the user groups that will be able to access protected resources within your React app, according to what you select and how you configure it afterward. I have chosen to use single tenant to have more control over who can be authorized.

· Declare roles for your application. This will be our RBAC mechanism.
Note that roles you declare here will be the roles you will check for in your React app later on. For the purpose of my application, I have named my role as Admin.

· Add a scope. This is necessary so that your application will actually initiate the SSO authentication flow once you redirect/popup to it in your React app. For some reason, the flow will not be triggered unless you have a scope set up. After you are done, your scope will look something similar to this:

Make sure you set Who can consent? to Admins only. Press the info icon for more details.

· Also, to further enhance the security of your application, you can add certificates and secrets by selecting the corresponding tab on the left side of your screen. This is optional, but I recommend you do so in any real-world scenario.

· OPTIONAL: Before we proceed, application owners can be added/changed here. This will allow other people within your organization to be able to modify application resources as need be (for instance if you move on to another project and you wish someone else to take over). The Owners tab can be located on the left side of your screen just below App roles.

I feel like the UI there is quite self-explanatory, so I will not cover the steps needed to add or remove an application owner.

Now that we are finished with configuring our application let us take a look at users and groups.

· Add group and its members. Navigate to the Azure portal home page, select Azure AD and the groups. From here it is quite straightforward what to do. However, pay attention to these two things: group type and membership type. The group type you want to select is Security (for obvious reasons, I hope), and the membership type should be Assigned — so that it is easier to control who gets access. I would also recommend setting owners of this group to the same list of people as your application owners. After your group is created, it should look something similar to this:

· Next, go back to the application you created earlier. Now, select Users and groups and then Add user/group. Look up the group you created in the previous step and select it. Now there is a link between your authorization group and your application. If you go back to the group you created and select Applications, you should see your application on the list.

This will conclude the Azure AD configuration setup, so now let us have a look at the code. There are several key components of your React application you will have to modify. I will try to cover them in as much detail as possible. Next, we will have to apply a “dark magic” component that will glue all this together. What I have discovered to be very useful, is a component called RouteGuard from Azure Samples. This is where the authorization part will actually take place. It is not the most optimal solution, and if you decide to create your own implementation of such component, who am I to stop you? So without further ado, I bring to you…

The code

First, let us have a look at the authConfig. Mine looks like this:

The key elements here are protectedResources and appRoles. And msalConfig, of course. It is hard to mess up the msalConfig, so I wanted to give the other 2 more attention. The values you need to input as your tenant ID and client ID can be located here:

The path under protectedResources is the path of your React web app that you need to protect. So that should be OK. But the scope needs to be exactly what it is in your Azure AD application configuration, located under Expose an API. Select Copy to clipboard if you do not want to miss anything. Same goes for your appRoles. Double check what you have entered under App roles in your Azure AD application configuration. Again, misconfiguration here will result in your authentication flow not working, and not being able to authorize users to protected resources within your app.

The next part of the application we will look at is index.tsx. Here, all the authentication logic will be implemented, so some key elements must be tended to.

The function handleRedirectPromise() needs to be invoked on every page load. To handle situations where an authentication flow has not been completed before a new one is triggered, we check for all accounts already registered with our instance and select one accordingly. We need to check that the account is with our tenant before we authorize it. Next, we use loginRedirect() to make sure our implicit flow is done homogeneously through the application. You may have noticed that I have been lazy when it comes to error handling, but there is one particular scenario that definitely needs to be taken care of. And that is BrowserAuthError. This error occurs whenever your users initiate concurrent authentication flows, meaning one flow does not conclude before another one is initiated. The other error type that needs to be handled is called InteractionRequiredAuthError. It seems without refreshing of sessions enforced this error does not kick in. However, should that be changed at a later time by your administrator, this error will occur, so you need to handle it (as you should anyway). Basically what you need to do is catch this error and initiate the authentication flow again, then everything will be fine. Finally, you need to inject your App instance with an instance of MSAL: <App pca={msalInstance} /> — this will make sure that it is available throughout your application.

So, now let us have a look at App.tsx:

Note that we add IPublicClientApplication as a parameter to the App instance. This parameter will be passed on to the MsalProvider, and, as mentioned earlier, persist login information across your entire application, as long as components you use are enclosed within MsalProvider.

The API usage here is a bit funky, but let us turn a blind eye to that for the time being. Let us rather take a look at the RouteGuard component:

RouteGuard will check if the user has the required role to utilize the component it protects. In case of the user has not yet authenticated to the application, index.tsx will redirect the user to the SSO page after the initial load of this component, then the component will reload once the user is redirected back.

Note that I am using a custom class IdTokenClaims since the one provided by MSAL does not contain the fields I need, which I have created myself as a workaround:

Audience (aud) is really up to you if you want to use it or not, but if you wish to check for roles, that really isn’t included in the library definition.

And that wraps up the code section for this guide.

To summarise the code section a little bit, and what we have achieved with it, let us go through the complete flow.

The current flow is like this:
1. Unauthenticated user navigates to the admin page.
2. RouteGuard checks if the user has the required role — failure.
3. index.tsx handles authentication (after RouteGuard renders <div></div>), redirects user to SSO page.
4. User authenticates to the application.
5. User is redirected back to the admin page.
6. RouteGuard checks if the user has the required role — success.

The original RouteGuard example only had role check in its implementation, but I have added additional checks to verify that the account user authenticated with is with the correct tenant, and has correct application claims also. This part is up to you, so some extra security can be added or removed according to your needs.

Conclusion

We have walked through the Azure AD configuration and set up the basic resources needed for our React application to interact with it. We have implemented both authentication and authorization and managed to keep it on par with our organization’s flows. This guide still needs some work to be complete, though. The RouteGuard component is flawed with respect to its use of the effect hook, as such implementation forces an “eternal loop”, so the hook really needs to be implemented correctly. Error handling needs some work done on it, also. There is a whole page on how to do it the right way. Also, I feel like I have not given enough credit to those who actually made sample code which I have used in my implementation, and this guide as well. For instance, this page helped a lot to understand the logic behind what is done in index.tsx. My job here really was to connect all the pieces together like in a puzzle. So, thanks to all those who contributed, and hopefully this guide will help you set up SSO authentication and RBAC with Azure AD in a React web app.

In my next article I will go through the token retrieval and verification process, so stay tuned. In the meantime, feel free to reach out to me on LinkedIn. Questions & comments are more than welcome!

--

--

Alexei Ivanov
Sopra Steria Norge

Alexei Ivanov is a senior fullstack developer and cloud engineer with Sopra Steria based in Oslo, Norway.