Role based authorization in Azure Functions with Azure AD and app roles
By: Philipp Bauknecht
Tags: Azure, Serverless, Azure Active Directory, Authorization, Azure Functions

Limit function to a role

With app roles configured and at least one users assigned it’s time to turn to Azure Functions. Let’s start with the project we created in the previous post: https://medium.com/medialesson/protecting-azure-function-apps-with-azure-ad-authentication-authorization-fd167ce4fe33

The logged in user’s assigned roles are part of the claims in the access token used for a request. So we can pull them from the ClaimsPrincipal object:

Note how we add the ClaimsPrincipal parameter to the function’s method. Each assigned role will be in a claim with the type “roles”.

Checking the user’s roles in each function method would be pretty repetitive though. A better approach is to create some form of middleware that checks the user’s roles before entering a function method. This middleware needs to be configurable so each function can decide which role it requires. To implement this requirement a possible way is to write a custom RoleAuthorizeAttribute that derives from FunctionInvocationFilterAttribute.

This attribute class needs to have a constructor parameter to allow to specify which role(s) are required for a function using the attribute.

The params keyword in the construction allows to pass in one or more role values. The method OnExecutingAsync gets called before a function method is executed when the attribute is used like this:

Important: Don’t remove the ClainsPrincipal parameter from the function as this defines which properties are passed into the arguments of the FunctionExecutionContext parameter in the attribute’s OnExecutingAsync method.

Now that the attribute is created and wired with a first function let’s implement the OnExecutingAsync method to decide whether to continue with the function executing based on the roles:

Note that there is a custom exception AuthorizationException that is being thrown when either claims are missing or the user’s roles in the claim don’t match the valid roles. The reason for throwing an exception is that I have yet to find another way of stopping the function’s method to execute and return a useful http status code result like in this case a 401.

So my approach is to a) throw a custom exception and the b) have the function’s class implement the IFunctionExceptionFilter interface. This interface allows to intercept exceptions and return http results. Like with the RoleAuthorizeAttribute we don’t want to implement this interface every time we need to use roles so let’s create a base class for all functions using roles:

To write a response this base class needs to have a IHttpContextAccessor injected in the constructor. Then we can filter for our custom AuthorizedException and return our 401 response.

Finally our function’s class needs to derive from BaseAuthorizedFunction. As we need to pass through the IHttpContextAccessor in the constructor we need to make the function’s class and method non static:

Summary

With this setup we have a reusable solution to limit execution of HttpTrigger functions (aka http apis) to not only authenticated users but also authorize based on the user’s assigned app roles. This works both in typical line of business as well as SaaS scenarios.