Frankly speaking, authentication is my least favorite thing to setup and get it running correctly. The OAuth authentication schemes brings some complicated concepts into our day-to-day job. Aspnet Core’s middleware already encapsulated most of the logic but you still see people asking how to setup Azure Active Directory Authentication or other similar authentication scheme correctly.
Search keywords like
jwt bearer token,
azure ad auth should provide you plentity of results to start with. However, you cannot avoid implement those key components to valdiate tokens, get user claims, token cache etc. Every web app we build, we will have to implement the same thing to protect the app.
Azure App Service has released a feature
Authentication/Authorization a while ago, but this is the first time to try it out in my work when I try to setup a new service. I decided to not implement the authentication logic but use the provided authentication mechanism by Azure App Service.
The following three articles by Azure should provide you the best knowledge to setup correctly and make it work. I would strongly suggest you to read through them if you want to setup the easy auth in your app service.
As soon as you are done with the setup, you are done with the authentication part. Your web app should redirect user to sign-in automatically without you code anything.
The next step is
Authorization. Notice that authorization is totally different from authentication, it happens after the user is authenticated. You might want to check if the user belongs to certain group before let them execute certain REST API. This article uses a role-based authorization as an exmaple how you can integrate authorization when you choose to use
App Service Authentication.
If you are using ASP.NET 4.6, the user principal claims should be populated automatically. However, if you are using Aspnet Core or Node.js, you would have to write some extra logic to handle it as the user claims are passed through your request headers. In this article we use Aspnet Core 2.1.
First of all, two import headers:
X-MS-CLIENT-PRINCIPAL-IDP. This tells you which authentication provider is used by the user, such as Azure Active Directory (value is
X-MS-CLIENT-PRINCIPAL. This is a base64 encoded string of user claims.
So the first thing is to read the user principal claims from the header value and set the
public class AuthorizationMiddleware : IMiddleware
Then you can setup a
appsettings.roles.json file where you can put security groups in the file.
To apply the roles in the
IConfiguration object, you will need to let Aspnet Core code know how to apply it. Note that there is a Azure KeyVault part in the code. This is used for
Managed Service Identity (MSI) where you do not need to provide any master key to access your keyvault both in local development and production. I really like this feature that makes the development and production more secure. If you want to integrated
Managed service Identity (MSI) into your web app, follow this instruction.
public class Program
Now, we can extend the
InvokeAsync method above in the middleware to include the security groups and roles. After we populate the
context.User, we are looking into Azure Active Directory and check the user’s security groups, then intersect with our definition in the
appsettings.roles.json. If there is an intersection, we should populate the corresponding roles into the user claims. Finally,
CanAccessApi method will decide if the user has permission to access certain api based on the roles of the user. If the user is not able to access the API,
401 UnAuthorized is returned.
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
Another key function we called from the above code is
GetTransitiveGroupMembershipAsync, which we call the Microsoft Graph API to figure out the user’s belonging security groups. Microsoft Graph API provides REST APIs to retreive information and our app service delegates the users to query Graph API so you will see we need to get a new token for this very purpose in the code. Of course, you need to add
Read Directory Data permission to your Azure Active Directory Application.
private async Task<IEnumerable<string>> GetTransitiveGroupMembershipAsync(HttpContext context)
In summary, we can put everything together into a Aspnet Core
Middleware where you can plugin to your Aspnet Core application easily to deal with the authorizations in Startup.cs. Ideally, if you are building the micro-services for a number of services, you should put the authorization at your front door, so all the micro-services do not need to worry about the user authorization at all.
public void ConfigureServices(IServiceCollection services)