Practical Azure: Secure a .NET Core Web API using Azure AD B2C.

Jithesh Chandrasekharan
codeburst
Published in
7 min readOct 21, 2020

--

The objective of this post is to understand how to secure a .NET Core web API using Azure AD B2C, and how to access that API from an Angular application.

In my previous post, we discussed setting up Azure AD B2C and registered our Angular application. So if you haven’t configured your B2C tenant please read the earlier post before continuing with this article. Just to make sure we all are on the same page, these are the steps we did in our previous post.

Now let's get started with registering an application in B2C tenant.

Step 1: Web API Authentication in B2C

Our Angular application used the OpenId Connect protocol for the sign-in process. Web API authentication uses the OAuth2.0 protocol for authentication. In this case, the access token we received as part of authentication is put in the HTTP request header for our HTTP requests. The web API validates the token and authorize your request. Here is a good explanation of OAuth2.0.

Let’s register our web API application in the B2C directory. Go to your B2C directory in the Azure portal and click register an application.

In this example, we will only be authorizing the users who are part of our directory (users can be part of this directory by logging into the Angular application). In the case of API, redirection isn’t necessary but the portal does require it so I would suggest providing a localhost address.

Adding Scopes

The next step is to add some scopes. Scopes are a kind of permission. A web application makes a request to a resource server on the behalf of a particular user. Scopes define what all actions and requests this web application can make on your behalf. Here is a good article to learn more about scopes.

Next, click on expose an API and add a scope. By default, “Application Id URI” is having your client id and not meaningful. Just give a meaningful name.

You can name your scope based on what the application might be requesting on behalf of a logged-in user. I am just giving ‘read_data’ as a scope name.

So now we have registered an API and created a scope for that API. The next step is to grant permission for Web Application (JitboxNg) to that scope of the API (we should have registered this Angular application in our previous post).

Go back to the JitboxNG application in the B2C portal. Select the API permissions tab and select our API and select the scopes.

Select the scopes you want to permit the application.

Now grant admin consent. By doing so, we are telling the tenant that — as an administrator — we do indeed want the JitboxNG web application to have access to these scopes implicitly (no consent screens needed).

This means that the JitboxNG website has implicit access to the following API’s scopes:

Now our Web API application is registered in B2C, it's time to create a .NET Core web API and connect it to B2C.

Step 2: Develop a .NET Core web API and add authorization

The following command will scaffold a web API with B2C authorization.

$ dotnet new webapi --auth IndividualB2C 
--aad-b2c-instance jitbox.b2clogin.com
--susi-policy-id B2C_1_susi
--client-id 6d7ac62e-f525-4e50-9c11-a834c8c2f171
--domain jitbox.onmicrosoft.com
--name JitBox.Api

— Instance: You can find it from the endpoint of your API in the Azure portal.
— Susi-policy: This is the user flow name you created for sign up and sign in.

The remaining parameters are self-explanatory and you will see it in the overview section of your API registration page in the Azure portal. By default, this will scaffold the web API with a WeatherForecast controller and add necessary entries to authorize the controller's endpoint.

# appsettings.json{
"AzureAdB2C": {
"Instance": "https://jitbox.b2clogin.com/",
"ClientId": "6d7ac62e-f555-4e50-9c11-a834c2c2f371",
"Domain": "jitbox.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_susi"
},

Note: By default, code generated will not have a proper “Instance” URL. Ensure that you fix that as shown above. Check the endpoints of your API and fix your instance.

Below is the startup class generated and it includes all authorization information. Ensure that you add CORS support as shown below:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
...
}

As shown above, now the controller is annotated with [Authorize].

The scaffolded application returns some hardcoded values for the weather forecast endpoint so I thought of adding a new endpoint to return weather based on the city. I am using Openweathermap’s free API to get the weather; all you need to do is sign-up and you will get an API key that supports free API calls.

Below is the endpoint that returns the weather based on the city (I have only tested US cities).

Run this application, it listens on localhost:5001. Try to fetch the API using postman.

As expected we got 401 (unauthorized). That means now our API is secure and only the user in B2C tenant can access this API. This marks the end of our second step. In the next step, we will update our sign-in/up policy to collect the ‘city’ attribute, so that we can fetch the city’s temperature.

Step 3: Update B2C sign-in/up policy

If you read the previous post, we know that the only user attribute we are collecting and claiming is the ‘display name’. But since we are returning weather based on the city, we need to update our user flow to collect and claim the city also.

Go to the Azure portal and select your B2C account and edit the user flow policy as shown below.

Add the city in claims.

Now let’s sign up a new user and see the identity token we are receiving. As expected, when you sign-up you will see the new city attribute along with the display name.

Successful signup will return back the identity token with the ‘city’ and ‘display name’ claims as shown below.

Since our authentication is successful this marks the end of step three. Let's update our Angular application to fetch the weather based on the user’s city.

Step 4: Call API securely from Angular application

Now let’s update our Angular app to request an access token with the scope of this API and call this API “passing token”. As a first step, I am adding a button ‘Get Temperature’ to call the API.

During the API call, we are acquiring the access token for that scope and specifying that token in the HTTP header to call the secured web API.

Now we have successfully called an API secured by B2C from our Angular App. This marks the end of this post.

I hope you enjoy the article, you can find the source code here.

--

--