Real world applications are composed of multiple components. Each component may itself be an application. For example, a web app may call another application which exposes only Web APIs.
In this article we will have look at this particular scenario and see how can we secure the calls using Azure AD.
Also, in this case, there are two deployed applications, one hosts only web app, the other hosts web APIs. Let’s see how can we secure Web API, Web App and how to get token in Web App to call Web API.
Securing Web API
We will have to register the API application in Azure AD. Then we will have to configure our web API application to use appropriate
Client ID and
Tenant ID. Also, we will have to configure middleware to allow only authenticated / authorized users to call the APIs.
Refer my previous blog article about securing web APIs for detailed steps.
Securing Web App
Refer my previous blog article about securing web app for detailed steps.
If you have followed all steps correctly till now, then you have two applications which are independently secured. The web app is not yet able to call Web API app. If you try to call it through web app, the call will return HTTP 401 unauthorized.
Azure AD API Permissions
In Web App Registrations, we will need to add the API permissions which are required to call the API we have created.
Login to Azure Portal and navigate to Azure Active Directory from left navigation menu. Select App Registrations under Azure AD. We will be able to see SampleWebApp and SampleWebApi both in the list view.
Click on SampleWebApp entry and select API permissions from the left navigation. Then if we click on “Add a permission” button, a new panel on the left side will be shown.
On the left side panel, we can select any API that we want to call from web app. As we want to call our own API (i.e. SampleWebApi), go to “My APIs” tab. This tab will show all API app registrations from the same Azure AD. Select SampleWebApi from the list.
Next, you will be asked to select the permissions. There are two types of permissions as shown in below snapshot
- Delegated permissions, select this when you want to call the API as the signed-in user. This is applicable for applications which allow end-users to sign in and perform some actions. This option means the API would be called on behalf of logged in user. This option is enabled and by default selected.
- Application Permissions, this is disabled by default for us, because SampleWebApp is not a background service. This should be selected only if the application is running as background service / daemon.
Select Delegated Permissions option. Anyway Application Permissions option would be disabled as our application is web application.
Also select the API permission
access_as_user and click on Add permissions button.
After adding it, the API permissions list would look similar to below snapshot.
Azure AD Client Secret
When any application calls secured Web API, that application becomes
confidential client application.
Confidential Client App
confidential client application can be
- A Web App which intends to call secured Web API
- A Web API which intends to call secured Web API
- A desktop application (WinForms or WPF)
- A background process / service / daemon
Azure AD also requires the application to prove it’s identity to ensure that only correct
confidential client application is requesting the tokens.
Confidential client application can prove it’s identity by two ways, either by presenting the certificate, or by presenting the client secret.
Certificates are issued by certificate authority. And buying certificates involve cost. So, for this demo, we will use Client Secret.
Generate Client Secret
Let’s see how to generate client Secret using Azure Portal.
SampleWebApp registration in Azure AD, select Certificates and Secrets and it will show a panel like below. Then click on New Client Secret.
A new popup will be shown. We need to enter Description and Expiry duration.
Expiry duration of 1 year is sufficiently long. Also, in my opinion, it is better to keep the secret changing, so that guessing it becomes more and more difficult.
After entering these two inputs, click on Add button.
Then it shows a client secret entry under Client Secrets section as shown below snapshot. Make sure to copy and keep it in a safe place. You won’t be able to access it again after you leave the portal.
Web App AppSettings.JSON
Let’s add the copied client secret value in
AppSettings.JSON as shown in below snippet. This
ClientSecret will be automatically picked up by middleware. No additional code is required to read client secret value.
Web App Startup.cs
There are two important modifications required in startup.cs
- AddWebAppCallsProtectedWebApi, this will enable the web app to call the protected web API. This middleware requires configuration and scope collection. The scope collection should include the full scope including API permission. (e.g.
- AddInMemoryTokenCaches, this will enable InMemory token cache serializer.
- AddDistributedMemoryCache, this will enable distributed memory cache implementation. This is helpful if you want to retain token caches even after your web app is restarted. On your development machine, even if you do not add this middleware, the solution will work.
In this article, we are going to use AddDistributedMemoryCache middleware for InMemory implementation. But we also have option to use Redis Cache or SQL table as the token cache.
Refer this sample for SQL cache configuration in startup.
The Startup.cs in the web application should be similar to below snapshot.
Calling Web API
For keeping the things simple, let’s try to add the API call from the
On high level, what we are going to do in this action is
- Get the token for the required scopes
- Set bearer token and in HTTP request
- Call the API using HttpClient object
- Get Response and Render on UI
Microsoft.Identity.Web maintains one token cache per user account for security and performance reasons.
When we registered middleware
AddWebAppCallsProtectedWebApi, it also registered dependency implementation for ITokenAcquisition interface. This TokenAcquisition implementation has method to get the token on behalf of the user.
To make use of this class, the TokenAcquisition should be injected in
HomeController and method
GetAccessTokenForUserAsync should be called on its instance.
Below is completed code for
Add below code to show result from weather forecast API in
Run and Verify
Now, all the configurations are done and we have added web API call.
Let’s run the Web API project and Web App project. The Web App will get redirected to Azure AD and will show login screen. After successful login, The MVC application will try to render Home controller’s Index action. This action will call Web API and will render the data on UI.
If you see page like below snapshot, that means our setup is running as expected.
If you want, you can download the sample solution from my GitHub repository. The solution has 3 projects, web api, razors view web app, mvc web app.
After downloading, you will just have to register the apps in Azure AD and update the
appsettings.json files with appropriate identifiers and client secrets.
I hope you enjoyed this article. Let me know your thoughts.