API SECURITY FOR DUMMIES | Authorization with Access Control List
API Security with ASP.NET Core 5.0 and Azure AD for Dummies

This blog is part of a complete blog series.

API security metaphor

If we get back to the party metaphor, the following steps are performed:

  1. The ticket desk gives each authenticated user a badge.
  2. The bodyguard only allows people with a valid badge, that are on the guest list.

In the context of API security, it goes like this:

  1. Azure AD returns an access token (JWT) in return for a successful authentication
  2. The API has a global security check to see if the consuming client id (azp claim) is on the allowed list

An Access Control List is ideal for these security requirements:

  • There is a limited number of applications that consumes the API (e.g. API is behind a gateway)
  • The user context should not be considered at al
  • The authorization must happen on the global API level

Implement the ACL on the API

Now it’s time to secure our API, by adding Access Control List authorization to the API.

From the previous part, you might remember that the daemon application could not successfully call the API.  Instead, a 500 Internal Server Error was thrown with this following exception message: IDW10201: Neither scope or roles claim was found in the bearer token.

The reason for this exception, is the fact that there is a default validation that checks if the access token contains a scope or roles.  In case of a daemon client, there is never a scope present, because the client credentials flow uses the /.default scope, which is not propagated in the access token.  Roles are supported for daemon applications, this will be tackled in the next part.  In our scenario, we just want a simple validation on the client id of the client application.

Luckily, we can override this default behavior and implement a ACL:

  • Open the PartyApi solution from the `02-with-authentication` folder
  • Add this setting to the AzureAd section of the appsettings.json file.  This disables the scope/role validation.
"AllowWebApiToBeAuthorizedByACL": true
  • Add the Access Control List to the AzureAd section of the appsettings.json file.
"AccessControlList": [ "<DAEMON-CLIENT-APP-CLIENT-ID>", "<USER-CLIENT-APP-CLIENT-ID>" ]
  • Update the AuthorizationPolicyBuilder in the Startup.cs file, to check that the azp claim is part of the configured Access Control List
var policy = new AuthorizationPolicyBuilder()
                 .RequireAuthenticatedUser()
                 .RequireClaim("azp", Configuration.GetSection("AzureAd:AccessControlList").Get<string[]>())
                 .Build();
  • From now on, calling the API will only succeed if the client application is allowed in the ACL

Conclusion

In this part, we have seen a simple, but effective way of implementing authorization via a configurable Access Control List.  This is the perfect scenario when you have a very limited number of client applications and you do not have to take into account a potential user context.  A good example is an API that sits behind an API gateway.  It is often sufficient to add the API gateway to the Access Control List of the backend API.

ABOUT

MEET THE YOUR AZURE COACH TEAM

Your Azure Coach is specialized in organizing Azure trainings that are infused with real-life experience. All our coaches are active consultants, who are very passionate and who love to share their Azure expertise with you.