Tech Blog: Azure App Service ‘Easy Auth’ and the .default Scope

Both Azure App Service and Function App provide a built in mechanism for providing token based authentication & authorisation (often known as ‘Easy Auth’) for your website or API. This is reasonably well documented, but there is one particularly important caveat which isn’t so obvious and will leave your app open to being called by a client which hasn’t been specifically granted permission unless a non default setting is enabled.

Although it is advisable to deploy Azure services using a IaC approach, such as via Terraform, let’s walk through the GUI settings to get to grips with what’s going on. I’ll use a Function App for the example but the same applies to an App Service.

Take a vanilla Function App deployment and take a look at the Authentication/Authorization settings. If you enable AD authentication, and use the express settings, you can see that it’s going to create a new App registration in Azure AD:

And it does, with an exposed API and a scope which a calling client can request when accessing your application :

‘Great’, you think, ‘now when someone calls my app they will need to get a token with that scope’.

But what if you have some other app registrations in your Azure AD which are using the client credentials code flow? Maybe for some unrelated 3rd party application?

As a default setting, any app registration can request the default scope of any other app registration. Unless you are doing further checking of the token scopes in code, this leaves your app open to being called by clients which haven’t been explicitly granted permission.

Let’s prove the case….

I create a new app registration and give it a client secret. I can then get an access token using the oauth2 client credentials code flow, requesting the .default scope of my function app.

As you can see, the client has been able to request a token scoped to my application without explicitly being granted permission. If you then use this token to call the API:

Oh dear. The client has been able to call my API.

To fix this, you need to find the registration for your function app in the ‘Enterprise Applications’ area of Azure AD. Under properties, toggle the ‘User Assignment Required’ setting. (And click ‘Save’, cos Microsoft).

Let’s get another access token and try again:

Excellent. The client can no longer request the .default scope, so it can no longer get a token, so it can no longer call my app. Problem solved!

If you are deploying services via Terraform, when you are creating the App Registration, you need to give it a service principal. When you do this, you need to also enable the “app_role_assignment_required” setting (link below). This will toggle on the setting we looked at in Enterprise Applications

https://www.terraform.io/docs/providers/azuread/r/service_principal.html#app_role_assignment_required-1

As you can see, it’s very easy to overlook this setting. Because it’s not the default, or clearly documented, I am willing to bet that there are a lot of app registrations able to call applications which their creators are not aware of. Definitely something to look out for when using this feature of Azure.