My Notes: Using Azure AD and MSAL for Application Authentication
When building an internal application you probably have authentication and authorization needs. If you already have a Single Sign On (SSO) provider like Auth0 or Okta then you are in pretty good hands as they both have great documentation and features to support these kinds of scenarios. For the rest of us, we need to get creative and use the tools we already have available. For some of us Azure AD may be that tool. If your business is already using Office 365 or Azure you may be able to use Azure AD to meet your internal authentication needs. To add convenience, you may even already have your desired users entered in Azure AD and organized into groups.
Because Azure AD uses OpenID Connect and JWT you can use whatever tools you want to work with it. I ended up using the MSAL libraries for JavaScript and ASP.NET Core. Azure AD has a lot of good documentation and there are little bits of knowledge scattered around their samples but I really felt that it was difficult to bring it all together into a working solution. Judging from the way the documentation was written and from the available samples it seems to me the use case they had in mind was for users wanting to build their own Graph Explorer. This post is just a collection of things that helped me bring it all together for my use case.
Creating an Application
Before you can use Azure AD for authentication you have to create an Azure AD Application in the poral. This Azure AD Application will control which of your applications can use it for authentication and what kinds of information will be provided about your user. To create an application, click on “App registrations” within the Azure AD portion of your Azure Portal. You can leave the redirect URL blank at first as you may not know what to use for it yet, you can change them later.
After the Azure AD application has been created, you need to get some values out of it to use when configuring your software:
- Client ID - This can be found in the Overview section of your application in the portal.
- Domain - This can be found in the Branding section of your application in the portal.
Note that you have a limited number of “SSO Applications” you can create on the O365 and Free tiers of Azure AD. I had a lot of trouble understanding the criteria for what makes an Azure AD Application count as an “SSO Application” but you may be able to use a single Azure AD Application to meet your needs.
Configuring an Application
Authentication
You will need to configure your redirect URLs that each application sends. If you have multiple services that will integrate with this application you can enter multiple redirect URLs for them. If you don’t know what these values are yet, you can enter them later.
When your Redirect URIs are not configured correctly, you may get an error message like this:
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: ‘ffa9e143-853a-4b45-8e03-d2cf6a5abaf1’
This error means that the redirect_url
that your service or app is using does not match what is configured in the Azure AD Redirect URIs list. You can find the actual used value in the HTTP request your browser sends to Microsoft by looking for the redirect_url
parameter. Note that it can take a minute for new values to work.
If you are using Implicit Flow for authentication you may need to check the “ID tokens” checkbox under Implicit grant. Your needs may vary and the error messages you get are pretty good at telling you what you need.
- Add redirect URI(s) to your application
- Enable OAuth 2.0 implicit grant for single-page applications - Possibly out of date
Manifest
While a bit of an odd user experience, if you want to enable groups in your token claims you will need to edit the Manifest JSON. To allow groups you need to add or edit the "groupMembershipClaims"
property as described in the documentation.
Token configuration
You can edit tokens/claims directly in the manifest, but I recommend using the provided tools on this screen when possible. Using the Token configuration screen you can add additional claims to your token if you think they may be useful. As an example you can add an ipaddr
claim using the “Add optional claim” tool. More likely, you will want to add group claims to your token so you can more easily restrict different areas of your app to different groups. Use the “Add groups claim” button to add group claims to your ID token. In my case I found that “Group ID” worked best for me. Note that when your services and apps request a token they will be given these optional claims even if they don’t ask for them, so no need to explicitly request them using scopes.
Working with JavaScript
The MSAL libraries from Microsoft help a lot to integrate with Azure AD but there are some quirks to be aware of.
Installation
When working with JavaScript you only need to install msal
. Working with Angular however is a bit more work as you may have to experiment with different versions of different packages before things work for you. I was able to get MSAL working with Angular 8 when I tried by using a beta version of the @azure/msal-angular
at ^1.0.0-beta.1
. Additionally there seems to be some confusion regarding if you should reference msal
or @azure/msal
, so I guess try them and see which one works for you 🤷.
Configuring
Configuring MSAL is mostly straightforward with the exception of a few quirks and deviations from the documentation that I ran into. You can navigate around the outdated documentation by using typescript or exploring the MSAL code yourself on GitHub.
The first odd bit that I had to work through was providing a working configuration for the protectedResourceMap
property. Instead of accepting an object or array it must be an instance from new Map<string, string[]>()
in Typescript or new Map()
in JavaScript. You can either feed an array of arrays into the constructor or call the .set
method directly. Either way though it makes configuring your application a bit painful and awkward as your environment.ts file (or whatever solution you use) may end up containing something like this:
|
|
In addition to the configuration troubles I had I was also surprised to find that if I wanted the SPA application to acquire an ID token I had to change the requested scopes to be the Client ID instead of the expected openid profile
. I’m sure this has to be wrong but I found a sample that demonstrated this and also can see it in the code for UserAgentApplication.ts .
Working with ASP.NET Core
Microsoft provided some samples to work with ASP.NET Core and OIDC but they all seem to have a reference to a project that I didn’t want to copy around. The good news is that this extra project isn’t doing a whole lot and you can study it to learn what is needed to get OIDC working with a standard ASP.NET Core setup: WebAppServiceCollectionExtensions.cs
- Azure AD OIDC Samples - Note that all the samples have a project reference to
Microsoft.Identity.Web
- “Microsoft.Identity.Web”
- Quickstart: Add sign-in with Microsoft to an ASP.NET Core web app
JWT Validation
Instead of having ASP.NET handle the full authentication flow, it can just simply validate tokens that a SPA application holds. Validating tokens should be as simple as any other JWT validation setup in ASP.NET.
You should have no trouble validating the audience, signing key, issuer, and lifetime.
The authority will be used to get the signing keys from the well-known document, should match your iss
claim from the token, and should match the tenants you are using.
The audience should be set to your Client ID defined in the Azure AD application.
I think the correct NameClaimType to use is "preferred_username"
based on the examples but I’m not positive.
Here is an example to get started with:
|
|
- Authority - Documentation about Authority
Other Tools and Links
- jwt.ms - Provides some additional information about the Azure AD claims that are in your tokens
- JWT - A great place to start learning about JWT.
- .well-known - The well known document for the “common” tenant.
- ID tokens - Documentation on Azure AD ID Tokens
- Access tokens
- Microsoft identity platform and Implicit grant flow