Original Photo by Agus Dietrich on Unsplash, Icon Microsoft

How to use AAD B2C with ASP.NET Core for AuthZ and Angular for AuthN

Since Azure Active Directory B2C works a bit different this article explains how to setup authorization with ASP.NET Core and authentication with Angular and Postman.

Philipp Bauknecht
medialesson
Published in
8 min readOct 26, 2022

--

Intro

Azure Active Directory B2C (AAD B2C) ist Microsoft’s IDM for “non-organizational” users like consumers. It has many similarities with the “regular” Azure Active Directory and some quirks. This article will walk through setting up a basic AAD B2C tenant in the Azure Portal and use it to secure a API and a Single Page Application.

#1 Setup AAD B2C

It all starts with creating a new AAD B2C tenant that we can use as Identity Management System (IDM). Therefore a Azure Subscription is required.

Create AAD B2C Tenant

First up let’s create a new resource in the Azure Portal and search for AAD B2C, give it a name and domain:

Once the tenant is created open it in the portal. B2C tenants are a bit unusual as they are resources inside the AAD tenant they have been created, e.g. company.com but also host their own tenant e.g. my.company.com. So work with the tenant it’s necessary to switch into the B2C tenant. This can be done directly from the resource’s Overview page by clicking on “Open B2C Tenant”:

Create a user flow

All workflows required for the authentication scenario are modelled using user flows. A user flow can for example provide the sign in or sign up feature for users. So to enable any interaction with our tenant for users we need to create a user flow first. In our case it’s handy to pick the combined “Sign up and sign in” flow which provides a combined UI for users to sign up as a new user and also to sign in for existing users. So under “Policies > User flows” > “New user flow” select “Sign up and sign in” and provide a simple initial configuration:

Important is the name of the user flow as we need to use this in different places later. User attributes and token claims define which attributes are part of the sign up user form and which properties are returned as claims in tokens after sign in.

Next up are app registrations. Those represent our app or a part of it that the user can authenticate from. To explain the idea here is a simplified system architecture:

While it’s possible to use just one app registration for both backend and frontend it’s recommend to have dedicated app registrations for different parties in our solution. This way we could e.g. permit different areas of a API using scopes to different clients.

Create app registration for the backend

Let’s start by creating the app registration for the backend from “App registrations > New registration”.

Setting account types or any other setting here is irrelevant as this app registration will never be directly used for authentication.

After creating the app registration we need to take a note of it’s client id:

This app registration needs to expose an API. This allows clients to request a OAuth2 access token with this app registration as audience and one or multiple scopes.

First thing is to set the App ID Uri under “Expose an API”:

Next we need to add at least one scope for our API:

After adding the scope we need to also take note of the full scope:

Create app registration for the frontend

Now on to the app registration representing our frontend. This time the configuration is important. As platform let’s choose SPA as we’re going to build an Angular app and http://localhost:4200 as redirect URI as this is our default address when running locally:

Again we need to take note of the client id:

The last step is now to grant permission for the frontend app registration to create OAuth2 access tokens for the backend app registration und “API permissions” > “Add a permission” > “My APIs”:

To enable this permission it’s important to grand admin consent on behalf of our tenant by clicking on “Grand admin consent…”:

Now we’re done with a minimal setup of the AAD B2C tenant.

#2 Authorize in a ASP.NET Core app

After creating a new empty ASP.NET Core app we need to add one NuGet package to handle authorization:

Microsoft.Identity.Web

Next we add authentication to our services as well as CORS (to enabled local testing between our backend and the Angular app as they will run on different localhost ports.

Note how we added RequireAuthorization() to the root route to restrict it to authorized users. Or course we also need to provide a configuration object with the key “AzureAdB2C”:

Note how we also specify the SignUpSignInPolicyId with the name of the user flow we created.

When running the app now it should return a 401 Unauthorized error as it’s now restricted to requests that present a valid access token with an audience claim containing the client id of the backend.

#3 Authenticate with AAD B2C in Postman

To test things before moving on to the frontend let’s try this using Postman. The interesting part here is how to create a OAuth2 access token. To create tokens in Postman we need to add Postman’s callback URL

https://oauth.pstmn.io/v1/callback

to the allowed redirect URIs in our frontend’s app registration under Authentication:

Note that it can take a couple of minutes of this change to be in effect.

With the callback URL added we can now create our request in Postman and setup the Authorization configuration:

Auth URL

This is the endpoint that Postman will open in the browser to show the sign in UI.

https://{YOUR_TENANT_NAME}.b2clogin.com/{YOUR_TENANT_DOMAIN_NAME}/{YOUR_USER_FLOW_NAME}/oauth2/v2.0/authorize

for example:

https://myexplainthecloud.b2clogin.com/myexplainthecloud.onmicrosoft.com/B2C_1_SignupSignin/oauth2/v2.0/authorize

Access Token URL

This is the endpoint that Postman will call with the authorization code obtained after successful sign in to exchange it for an access token.

https://{YOUR_TENANT_NAME}.b2clogin.com/{YOUR_TENANT_DOMAIN_NAME}/{YOUR_USER_FLOW_NAME}/oauth2/v2.0/token

for example:

https://myexplainthecloud.b2clogin.com/myexplainthecloud.onmicrosoft.com/B2C_1_SignupSignin/oauth2/v2.0/token

Client ID

This is the client id of your frontend app registration

Scope

The full name of the scope we’ve defined when we exposed the API in the backend’s app registration, e.g.

https://myexplainthecloud.onmicrosoft.com/backend/All

After calling “Get New Access Token” the browser opens and after successful sign in Postman should show us our access token:

When inspecting this token e.g. using JWT.io it will show the backend’s client id as the audience in the claim “aud” and our previously defined scope “all” in the claim “scp”.

When sending the request now in Postman to our backend we should get a success response with status code 200 instead of 401 when calling without a token.

#4 Authenticate with AAD B2C in Angular

With the backend ready and secured let’s turn our attention to the frontend. First step is to create a new Angular app with routing enabled and add the Microsoft Authentication Library (MSAL) as 2 additional NPM packages to the project:

npm i @azure/msal-angular --save
npm i @azure/msal-browser --save

In the environment.ts we can add our authentication configuration:

Next we need to import and configure the MSAL library in our app module. This includes:

  • Importing the HttpClientModule so we can do requests to our backend
  • Create a new client application as part of the MSAL module import and configure it with the values from our environment
  • Define which cache to use for storing sign in information
  • A guard configuration, this is how the MSAL route guard will handle authentication e.g. redirect to the sign in UI of our IDM
  • A interceptor configuration, this is a list of known routes (in our case our backend’s url) and which scope is required. This has the effect that when calling such a route MSAL will intercept and try to obtain an access token for the defined scope. This access token will then be added to the original request’s header.

To test authentication with a route guard let’s create a new component:

ng g c home

and add it as a route with a MsalGuard:

finally replace the content of our app component with a router outlet:

When running the Angular app now we should immediately be redirected to the sign in UI of AAD B2C and after successful sign in be redirected to our home component.

#5 Call the backend

As a last step let’s call the backend from the Angular app. Our interceptor configuration should make sure that the correct access token is obtained and added to the request.

When running the Angular app now we should see some interesting stuff happenening on the network:

So there is now first a call to the AAD B2C’s token endpoint that obtains the access token and then there is the actual call to our backend using that token in the header. And of course that call now return a status code 200 as we’re proberly authorized.

Summary

I hope this gives a good overview and also a jumpstart as the information of how to setup this end 2 end and which values to use when in where is scattered across many sources.

--

--

Philipp Bauknecht
medialesson

CEO @ medialesson. Microsoft Regional Director & MVP Windows Development. Father of identical twins. Passionate about great User Interfaces, NYC & Steaks