How to secure Azure Functions API with IdentityServer4.

With custom handler and without Azure API Management.

Stas(Stanislav) Lebedenko
ITNEXT

--

Photo by Skitterphoto from Pexels.

Azure Functions have a rich functionality in terms of security and authentication, but options for custom auth are limited. And you have to create your own JWT token handler to work with an Identity Server 4 based provider. There are several articles online on this topic, but none of them matched my needs exactly, so I decided to share my solution as well.

TLDR; I will explain how to validate the bearer token issued by Identity Server 4. And I will share code samples of a handler that is verifying token signature and audience via JWKS endpoint or local key value.

I want to emphasize that the proper and expensive way to validate requests is to use the Azure API Management facade. Although there is a serverless tier of API Management, it has significant limitations in terms of functionality and cold start.

Update 2020–06–05: I have a follow-up for this article: Securing Azure Functions with API Management and IdentityServer4

Authentication options in Azure App Service

Platform options include Azure AD and four EasyAuth providers like Facebook, Google, Twitter, and a Microsoft account. They can be set up via the Azure Portal App Service configuration for Authentication/Authorization.

There is a hacky way to add an Identity Server 4 endpoint via the custom Azure AD dialog, but I strongly advise against this. Platform behavior can change any minute and it’s a highway to disaster.

Authentication providers supported by App Service.

Function level authentication options

There are several authorization levels available at the function code level.

  • Anonymous - all requests are accepted.
  • Function - function code should be passed via request parameter.
  • Admin - any host key has to be passed via request parameter.
  • System - the master key has to be passed via request parameter.
Function management page with authentication keys.

Identity server.

Identity Server 4 fully implements the OIDC specification and usually, there is middleware that validates tokens for you, but its not the case with Functions. So let’s recall what needs to be checked - a bearer token signature, issuer, and audience. This information can be obtained from a discovery endpoint of any OIDC compliant provider.

The discovery endpoint can be used to retrieve metadata about your IdentityServer — it returns information like the issuer name, key material, supported scopes etc. Example.

When you visit that endpoint, you can find all sorts of information, but the most important thing is the link to the JWKS endpoint. Because there you can find an open part of an RSA key, that is used for token encryption.

JSON Web Key Set (JWKS) is a set of keys containing the public keys that should be used to verify any JSON Web Token (JWT) issued by the authorization server. Example.

The last thing to recall is why there is a need for an Audience check because different applications can be registered on the same Identity Server. So it’s necessary to check if the client has access to this particular application.

The audience of a token is the intended recipient of the token.

Solution.

The action steps are pretty simple.

  • Enable anonymous authentication in a function.
  • Retrieve certificate signature from JWKS endpoint or local configuration.
  • Add a custom handler for token validation.
  • Test solution via Postman locally and in Staging.
  • Set daily memory time quota on Function App.
Azure function with an anonymous authorization level.

Please be aware, that functions authorization level is to anonymous, so you should set daily memory time quota to estimated GB/s value for Function App. And create an alert for excessive application usage. Denial of wallet attack is a real thing.

Quota setting via Platform features => Function app settings.

You can use Azure CLI for daily memory quota setup.

Azure CLI command to set quota.

So, let’s start with dependency injection. A token signature is publically available via JWKS endpoint, so you can embed it in the application configuration to avoid extra HTTP requests. And it’s better to keep all secrets in Azure KeyVault for easy rotation and security.

Let’s proceed with a Key retriever helper.

There is a problem with the method above. When you add a signing key to KeyVault, you can miss the future moment when the key is renewed. To avoid this issue the method below will get data from JWKS endpoint via an HTTP request.

Function code for token validation.

Conclusion.

Its a mixed bag solution, but it will do the trick. I will continue the authentication topic in the next article, by covering bearer token validation via Azure API Management.

That’s it, thanks for reading. Cheers!

PS. There are more options, such as OIDC Discovery endpoint handler and Reference tokes - links below.

--

--

Writer for

Azure MVP | MCT | Software/Cloud Architect | Dev | https://github.com/staslebedenko | Odesa MS .NET/Azure group | Serverless fan 🙃| IT2School/AtomSpace