In this article, we will use Azure AD to secure the Web API. We are going to use MSAL for this demonstration. MSAL stands for Microsoft Authentication Library.
Please note that you will need Azure subscription to follow the steps in the article. If you don’t have an Azure subscription, create a free account before you begin.
What is MSAL ?
Microsoft Authentication Library (MSAL) enables developers to acquire tokens from the Microsoft identity platform endpoint in order to access secured web APIs. You might have more questions about why one should use this library. Please refer documentation for more details on this topic.
One important thing to note is, we are going to use Microsoft.Identity.Web nuget package.
Microsoft Identity Web is a library which contains a set of reusable classes used in conjunction with ASP .NET Core for integrating with the Microsoft identity platform (formerly Azure AD v2.0 endpoint) and AAD B2C.
Microsoft Identity Web also leverages Microsoft Authentication Library (MSAL), which will fetch the tokens and provides token cache extensibility.
Create Web API project
Create a ASP .NET Core Web API project using Visual Studio 2019. As shown in below snapshot, make sure that .NET Core and ASP .NET Core 3.1 is selected in the dialog and API type of project is selected.
Now, you can run the application using Visual Studio to check the URL of your web API and ensure that the GET call returns you the result with 200 OK status as shown in below snapshot.
Now, you have a working Web API.
Azure AD App Registration
Now you can go to Azure Portal and Login to your Azure subscription.
Select Azure Active Directory from side navigation pane. This will open new panel which shows overview of Azure Active Directory.
Now Select App Registrations and click on “+ New Registration” button.
Enter a readable name for the API registration. Make sure you select Web API option under Platform Configuration as shown in below snapshot.
Then click on Register button. New application would be registered and you can see that under App Registrations menu.
Accepted Token Version
Microsoft Identity Platform Endpoint can issue v1.0 tokens or v2.0 tokens. Now, which input of App Registration decides which token version would be used
There is a section with name Supported Account Types –
- If the value of Supported account types is Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com), the accepted token version is v2.0.
- Otherwise, the accepted token version is v1.0.
But if you want, you can change this value even after registering the applications. Below are the steps for the same:
- Login to Azure Portal and Select Azure active directory from left navigation and App Registrations.
- Then select your app and then select Manifest.
- Find the property accessTokenAcceptedVersion in the manifest.
- The value specifies to Azure Active Directory (Azure AD) which token version the web API accepts.
- If the value is 2, the web API accepts v2.0 tokens.
- If the value is null, the web API accepts v1.0 tokens.
- If you changed the token version, select Save.
Azure AD Define Scope
Now, again go to App Registrations under Azure Active Directory and then select SampleWebApi applications.
Because your application is exposing APIs, select Expose an API option from the left side menu.
Then click on Add a scope. A scope is OAuth 2.0 concept. Basically it is a permission which is required for any other app which wants to call your web Api app.
When you click on Add a scope, new dialog opens on right and it shows Application ID URI
which is as shown in below snapshot. You can also opt to change it. If you want to change it, the new application ID URI needs to be globally unique. For now, let’s keep the default value and click on Save and continue
button.
Next, you will be shown a new dialog where you can provide below details:
- Scope name, name for the scope. Enter
accesss_as_user
. The complete scope name should include application id URI. - Set Who can consent? to
Admins and users
- Set Admin consent display name to text shown in snapshot
- Set Admin consent description to text shown in snapshot
- Set User consent display name to text shown in snapshot
- Set User consent description to text shown in snapshot
- Set State to Enabled
The 4 bullet points about consent display name and description are actually texts. These texts are shown by Azure AD after authentication to take consent from Users and Admins.
Then click on Add Scope button. This will add a new scope in the App Registration – SampleWebApi.
NuGet Package
Add below NuGet Package to the Web API project you created in the first step.
This package is specifically used for web applications, which sign-in users, and protected web APIs, which optionally call downstream web APIs.
AppSettings.json
Now, all the steps which were required to register the API application in Azure AD. Next, step is to modify application configurations.
As a first step of application configurations, let’s add the following configuration section in appsettings.json
Startup.cs
Next, go to startup.cs and modify two things:
- In ConfigureServices method, add Protected Web API middleware using statement :
services.AddProtectedWebApi(Configuration);
- In Configure method, make sure you use Authentication and Authorization middleware.
Below code snippet shows how your Startup looks like:
Decorate Controllers
Last but not least, is to ensure you tell framework to authorize all incoming requests to your API.
For this purpose, you will have to add [Authorize] attribute on your ApiController classes.
Run and Verify
Our API contains only GET method. So we can open browser and try to access the URL from browser. If you open browser debugging tools, and check the Network tab, you would be able to see 401 unauthorized error as shown in below snapshot.
So, we have successfully secured our web API. Now no application can call our API until that application has valid access token.
This article was only about securing your Web API. In next article, I would write about how to call this secure API, from a ASP .NET Core Web Application.
You can have a look at complete solution at my GitHub Repository.
Will we be able to validate a v1 token using this code?
I have a token which when decoded has an “iss”: “https://sts.windows.net/{tenantid}/”
Wondering how I’ll validate this token in my API.
Thanks!
Awesome ! I did not cover token validation in this article because I thought I would write a separate article about it. Some basic validations can be done using the TokenValidationParmaters from the options as shown below. Hope this helps.
`.AddProtectedWebApi(options =>
{
options.TokenValidationParameters.ValidateIssuer = true;
}`
Can i show token and user profile within Action/Controller?
I did not understand what do you mean by user profile.
You can read the token for sure. Configure startup to use In Memory token Cache and then inject ITokenAcquisition in the controller.
// This line should give you token
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
// Startup.cs – In memory token cache
services.AddInMemoryTokenCaches();
Hi Manoj, Thanks for the example. Did you write the next article, about how to call this secure API, from a ASP .NET Core Web Application or via Postman? If so please share the link to it.
There are two articles:
1. Angular app calling Azure AD Protected web API ( https://manojchoudhari.wordpress.com/2020/05/05/angular-app-and-azure-ad-protected-web-api-using-msal/)
2. .NET Core web app calling Azure AD Protected API (https://manojchoudhari.wordpress.com/2020/05/04/securing-net-core-web-app-calling-web-api-using-msal-and-azure-ad/)
Hi Manoj,
Thank you for sharing the article. I found it very useful. However
I had to update the WebAppMVC HomeController.cs code line #31 because when I tried using the scope string as mentioned in your article it gave me an error. Also I had to set
“accessTokenAcceptedVersion”: 2, in the manifest files for both the registered apps.
//// Acquire the access token.
string[] scopes = new string[] { “https://MyDomain.onmicrosoft.com/d97d2926-ba0a-483d-9f03-80ec83c26164/access_as_user” };
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
I also had to update the WebAppMVC Startup.cs code as:
services.AddWebAppCallsProtectedWebApi(Configuration, initialScopes: new string[] { “user.read”, “https://MyDomain.onmicrosoft.com/d97d2926-ba0a-483d-9f03-80ec83c26164/access_as_user” })
.AddInMemoryTokenCaches();
It would be hard for me to point out exact error without looking at everything. Maybe it would be helpful for you if you can compare all steps again with the steps mentioned the blog.
Hi Manoj, Have you used Azure API Management portal with the API that you have secured using AD B2C? If so, can you also share your experience and how to achieved it.
You can refer to this article to know how to publish API via Azure API management. As far as I know, you would not need any additional configurations on API management if your backend API is secured using Azure AD B2C.
https://manojchoudhari.wordpress.com/2019/03/13/azure-api-management-from-api-consumer-perspective/