Secure Azure Functions with JWT access tokens

I have completely rewritten this post. You can find the original post here.

Out of the box it is only possible to secure your Azure Functions via Function Keys (API-Keys), which sometimes might not fit into your requirements. When using HttpTrigger we luckily have access to the current request and are therefor able to implement our own custom authentication/authorization methods. You could for example use JWT access tokens issued by an OpenID provider to control authentication/authorization.

In this post you learn how to validate JWT access tokens and controlling access to your Azure Function.

It is very important that you set the authorization level to anonymous, since we want to skip all checks done by Azure Functions. Then we need to add the “authentication boilerplate code” to every function, we want to protect with JWT access tokens. Unfortunately there is currently no generic way to add this, e.g. via attributes.

Here we use a ConfigurationManager in order to retrieve the signing keys from the OpenID provider. It is very important to have the ConfigurationManager as a static, since it is caching the configuration in order to reduce HTTP requests to the OpenID provider. The ConfigurationManager refreshes the configuration after configurable timeouts. Next in the ValidateTokenAsync method we setup TokenValidationParameter. Here we want to enable as much validation as possible.

Once we configured the validation parameters, we call ValidateToken. If the token can not be validated a SecurityTokenException is thrown. There are several derived exceptions, but in this case we just care for the SecurityTokenSignatureKeyNotFoundException exception, which is thrown if the JwtSecurityTokenHandler can not find the signature keys, that are specified in the JWT. This could be the case, when the issuer changed its signature keys, after the ConfigurationManager fetched the configuration. Therefore we trigger a refresh on the ConfigurationManger and retry to validate the JWT.

If the validation is successful we return a ClaimsPrincipal which contains the claims provided by the token.

If you are not using OpenID you need to change the ConfigurationManager options. Alternatively you can remove the ConfigurationManger and provide static signing keys via the TokenValidationParameters.