Adding authentication to your HTTP triggered Azure Functions
Azure Functions are great! HTTP triggered Azure Functions are also great, but there’s one downside. All HTTP triggered Azure Functions are publicly available. While this might be useful in a lot of scenario’s, it’s also quite possible you don’t want ‘strangers’ hitting your public endpoints all the time.
One way you can solve this is by adding a small bit of authentication on your Azure Functions.
For HTTP Triggered functions you can specify the level of authority one needs to have in order to execute it. There are five levels you can choose from. It’s Anonymous
, Function
, Admin
, System
and User
. When using C# you can specify the authorization level in the HttpTrigger
-attribute, you can also specify this in the function.json
file of course. If you want a Function to be accessed by anyone, the following piece of code will work because the authorization is set to Anonymous
.
[FunctionName("Anonymous")]
public static HttpResponseMessage Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
HttpRequestMessage req,
ILogger logger)
{
// your code
return req.CreateResponse(HttpStatusCode.OK);
}
If you want to use any of the other levels, just change the AuthorizationLevel
enum to any of the other values corresponding to the level of access you want. I’ve created a sample project on GitHub containing several Azure Functions with different authorization levels so you can test out the difference in the authorization levels yourself. Keep in mind, when running the Azure Functions locally, the authorization attribute is ignored and you can call any Function no matter which level is specified.
Whenever a different level a different level as Anonymous
is used, the caller has to specify an additional parameter in the request in order to get authorized to use the Azure Function. Adding this additional parameter can be done in 2 different ways.
The first one is adding a code
-parameter to the querystring which value contains the secret necessary for calling the Azure Function. When using this approach, a request can look like this: https://[myFunctionApp].azurewebsites.net/api/myFunction?code=theSecretCode
Another approach is to add this secret value in the header of your request. If this is your preferred way, you can add a header called x-functions-key
which value has to contain the secret code to access the Azure Function.
There are no real pros or cons to any of these two approaches, it quite depends on your solution needs and how you want to integrate these Functions.
Which level should I choose?
Well, it depends.
The Anonymous
level is pretty straightforward, so I’ll skip this one.
The User
level is also fairly simple, as it’s not supported (yet). From what I understand, this level can and will be used in the future in order to support custom authorization mechanisms (EasyAuth). There’s an issue on GitHub which tracks this feature.
The Function
level should be used if you want to give some other system (or user) access to this specific Azure Function. You will need to create a Function Key which the end-user/system will have to specify in the request they are making to the Azure Function. If this Function Key is used for a different Azure Function, it won’t get accepted and the caller will receive a 401 Unauthorized
.
Only ones left are the Admin
and System
levels. Both of them are fairly similar, they work with so-called Host Keys. These Host Keys work on all Azure Functions which are deployed on the same system (Function App). This is different from the earlier mentioned Function Keys, which only work for one specific function.
The main difference between these two is, System
only works with the _master
host key. The Admin
level should also work with all of the other defined host keys. I’m writing the word’ ‘should’, because I couldn’t get this level to work with any of the other host keys. Both only appeared to be working with the defined _master
key. This might have been a glitch at the time, but it’s good to investigate once you get started with this.
How do I set up those keys?
Sadly, you can’t specify them via an ARM template (yet?). My guess is this will never be possible as it’s something you want to manage yourself per environment. So how to proceed? Well head to the Azure Portal and check out the Azure Function you want to see or create keys for.
You can manage the keys for each Azure Function in the portal and even create new ones if you like.
I probably don’t have to mention this, but just to be on the safe side, you don’t want to distribute these keys to a client-side application. The reason for this is pretty obvious, it’s because the key will be sent in the request, therefore it’s not a secret anymore. Anyone can check out this request and see which key is sent to the Azure Function.
You only want to use these keys (both Function Keys and Host Keys) when making requests between server-side applications. This way your keys will never be exposed to the outside world and minimize the chance of a key getting compromised. If for some reason a key does become compromised you can Renew or Revoke a key.
One gotcha!
There’s one gotcha when creating an HTTP Triggered Function with the Admin
authorization level. You can’t prefix these Functions with the term ‘Admin’. For example, when creating a function called ‘AdministratorActionWhichDoesSomethingImportant
’ you won’t be able to deploy and run it. You’ll receive an error there’s a routing conflict.
[21-8-2018 19:07:41] The following 1 functions are in error:
[21-8-2018 19:07:41] AdministratorActionWhichDoesSomethingImportant : The specified route conflicts with one or more built in routes.
Or when navigating to the Function in the portal you’ll get this error message popped up.
Probably something you want to know in advance, before designing your complete API with Azure Functions.