Here I take a quick look at the new MSAL Angular library preview for Azure B2C, securing both ASP.NET Core Web API & Azure Function resources and calling these from an Angular web app.
Microsoft is clearly working to make Azure AD B2C as easy to integrate into SPA's as other identity services are (I'm looking at you, Auth0). The new Angular MSAL library makes working with Azure AD B2C much simpler - at least from the Angular side. I was evaluating authentication options for a POC a couple of months ago, building out three options - self-hosted with OpenIddict, and hosted with Auth0 and Azure B2C. The app was using Azure services with an Angular frontend and my initial preference had been to stick with Azure for the authentication, taking advantage of the integration in Azure (e.g. Easy Auth for web & function apps).
My experience with Azure B2C left me feeling quite frustrated. I spent hours trying to get it all working, battling with confusing documentation & sample applications that didn't seem to work properly. I did eventually manage to get it up and running using the MSAL.js library directly in Angular, building out my own services around the library, but the whole thing didn't feel great from either the user or developer perspectives. (Edit: to be fair, I did actually have to build out services in Angular for Auth0 as well - I just found more/better quality examples of these around to use as a starting point).
In contrast to Azure B2C, Auth0 was an absolute breeze to setup, both on the backend and in my Angular app. It's very well documented, with a great user experience. It looked professional.
OpenIddict in an ASP.NET Core app was easy enough to get up and running with as well, and there are some good examples out there (I particularly like this one). This also brings the benefit of seamless login and registration experiences for the user, maintaining control of user data, etc - but with the added burden of additional boilerplate and having to host & manage it. As this POC wasn't likely to go out into the wild any time soon (if at all) I opted for self-hosting with OpenIddict, with a plan to switch later if it made sense.
Anyway, fast forward a couple of months. A lot can change in a short time with cloud services so I thought I'd revisit this. Not much new on the user experience side with B2C that I could find, but I did notice the Github repo for MSAL had been pretty active, and the readme now pointed to an Angular wrapper for MSAL now being available.
It looks like this was released a couple of weeks ago, at the end of July, so I thought I'd give this a go and see if it came closer to the Auth0 with Angular experience.
I created a new ASP.NET Core web application with the Angular template.
The default Angular template includes a fetch data demo route, retrieving weather forecast data from an included Web API controller in our backend - perfect for our test, so our objective is to secure this via Azure B2C authentication. I'm also going to add an Azure Function project and secure this as well.
First thing to do is to add the new new msal-angular package with
npm install @azure/msal-angular --save in the ClientApp folder. At the time of writing the package version is 0.1.1.
While NPM was going about its business, I checked on my Azure B2C setup. I have a test application setup in Azure B2C as below - all I did was change the update the redirect urls.
I modified my app.module.ts file in Angular to the following, as per the readme on the Angular MSAL repo. Here we're initialising the authentication module, plus a route guard for the Fetch Values route so that the user will be prompted to login when they browse to this route. We're also using the included interceptor implementation to attach the access tokens to API requests automatically.
We're going to be fetching values from both the local Web API and an Azure Function. I needed to set the Azure Function Url as a protected resource and map it to a scope, otherwise the interceptor didn't attach the access token to the authorization header automatically. It did for the Web API resource though.
I've also chosen to use the popup login window rather than redirect, enabled verbose logging, and added a logout button on the left nav bar which displays when the user is logged in.
At this point we can test the login/register functionality. This is when we start up:
And when we click on the Fetch data nav link, we get our (currently unbranded) login/register popup:
And after logging in, we get the data from our Web API controller:
We haven't secured our Web API controller yet, so let's do that next. I'm setting our ASP.NET Core Web API to use Azure authentication and secure the controller with an
[Authorize] attribute. Additional code required for Startup.cs and appsettings.json files is below:
And that should all be working. Nice and easy, except I got stuck here for about half an hour getting 401 responses from the Web API before I figured out I'd missed out the
app.AddAuthentication() line out of the Startup.cs file.
And finally, lets add a new Function project. I'm adding a Bearer Token Validator class, which I have others to thank for the the code & flow - notably Boris Wilhelms, Ben Chartrand and James Randall.
Here's the code:
And with an update to our fetch data component in Angular we can now see the flow through with it all working. You'll need to set both projects to startup in VS.
Here's our loading screen after we've authenticated:
First our Web API returns data:
Then a second or two later our Function returns data:
Here's our Function console output, logging the User ID for the request:
I was able to get everything up and running over the course an evening, with the Angular part working with Azure B2C in just a few minutes by adding the few lines of code to the app.module.ts file. I'm writing this with the benefit of hindsight and some experience with B2C but it's nice to see this getting even easier. I'd argue it's as easy to use Azure B2C in Angular as it is with Auth0 now.
Microsoft still have more work to do on the overall experience of using B2C in my opinion, from both the user and developer/ops sides, but things are definitely heading in the right direction and I'm following B2C closely. I'm still on the fence with regards to using this in a new project I'm starting, but I'm going to spend more time with B2C and I'll post further about my experiences.
Next items on the list are social logins, customising the hosted forms, exploring resource owner password credentials flow (i.e. using your own login form) that's currently in preview, and also - very importantly - getting a better grip on the overall costs. Costs are concerning in general with hosted identity services, particularly when they're consumption based like B2C - and from my understanding have token refreshes count towards your use in addition to actual logins.
Anyway, I hope you were able to take something from this post & please feel free to reach out with any questions.
Code for this example is available on Github.
A Microsoft project with more examples is also available on Github