Microsoft.Identity.Web, Azure Active Directory, and SPAs
If you've been following along with this series on demystifying Azure Active Directory for developers - showing how all the various topics fit together, including using the new Microsoft.Identity.Web
library to illustrate various points - you've probably noticed I've only talked about ASP.NET Core web applications and web APIs.
But what about Single Page Applications - or SPAs? Can they integrate with an ASP.NET Core Web API using the Microsoft.Identity.Web
library protected by Azure AD?
Yes. Why yes they can.
Creating a SPA to Access an ASP.NET Core Web API
SPAs by their nature are all JavaScript-based. But the library we've been using to protect the Web API is .NET based.
So how does it work when the sign-in flow is started by a JavaScript library, but the resource is protected by a .NET-based library?
Way back in the first part of this series I mentioned that Azure AD was all standards based - like OpenID Connect and OAuth.
I stated back then that the benefit of that was you didn't have to roll your own library to interact with Azure AD - let somebody else do it for you and then you can rely on it. Don't reinvent the wheel.
Another benefit is... as long as a library implements the standard - they won't have any issues communicating with each other.
So let's get a SPA into the mix of our apps.
Updates to the Web API
This is easy - there are no updates. The Microsoft.Identity.Web
library is standards based.
(Other than making sure CORS is setup).
Your job here is done.
Creating the SPA
There are a couple of steps here. Configuring the Azure AD application to model the SPA and creating the SPA itself.
Azure AD Application Changes
There are a couple steps you need to do in order to make sure the Active Directory Applications can handle SPAs without any issues.
Which Azure AD Application Should You Use?
You already created an Azure AD Application to model the ASP.NET Core web application - can you just reuse that for the SPA?
Yes.
Or, you could create a new one.
Personally, I usually group together any "real-life" apps into the same Azure AD application if they perform the same general functionality. So if the SPA is just a SPA version of the ASP.NET Core web application - reuse the same Azure AD application. If not, create a new one.
Either way, you need to add a specific reply URL to handle the SPA. It's a little different than for a web app reply URL - but still straightforward to do.
Follow these directions and you'll be up and running in no time.
Building the SPA
The SPA will use the MSAL.js library to communicate with Azure AD.
MSAL.js is awesome (in fact, Microsoft.Identity.Web
wraps the .NET version of MSAL).
There's plenty of documentation around setting up a Single Page Application to authenticate with Azure AD and get an access token.
Follow those docs to get the SPA app up. And then there are a couple of quick changes necessary to the code in order to get it to call your Web API.
SPA Code Changes
There are a few changes to app.module.ts
that are needed.
The first is to the MsalModule.forRoot
node.
You'll need to make changes to include the correct clientId
, authority
, and redirectUrl
.
And note the authority will be of the form: https://login.microsoftonline.com/{YOUR TENTANT ID}
Then further down under consentScopes
. Add a new entry into that array with the full value of the scope of the API.
For example: api://YOUR-WEB-API-CLIENT-ID/access_as_user
Then finally under protectedResourceMap
you want to have a new entry for the API being called along with the scopes needed.
It'll look like this:
protectedResourceMap: [
['https://localhost:5003/weatherforecast', ['api://YOUR-WEB-API-CLIENT-ID/access_as_user']]
Finally - go to profile.component.ts
and change the value of const GRAPH_ENDPOINT
to be the url of the web api you are calling. (The same one from the protectedResourceMap
.
That's it.
Of course you're bending the pre-existing sample to work - but it should give you an idea of what's involved overall.
That's It!
That's all there is to it.
The Web API using the Microsoft.Identity.Web
library stays exactly the same.
The library implements standards, so as long as any requests to it also implement the standards - we're good to go.
And as such - it doesn't matter what client type originates the request to the Web API. As long as the token that gets passed was obtained from Azure AD and is standards based (and how else would you get the token in the first place?) Everything will work.
Have at it - and happy coding!