Protect Azure Functions with API Keys using Azure API Management - Part 2
Tags: azure, azurefunctions, dotnet, api
Published: 2023-09-06 16:49:46

In Part 1 of this series we created two Azure Functions protected by function keys and published those to Azure.  In this part we're going to use [Azure API Management](https://azure.microsoft.com/en-gb/products/api-management) to wrap those functions and provide access via API Keys.

## Create an API Management service

Head back into Azure create a new resource choosing **API Management**

![Create API Management](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgmreufc53i9sj2tfllx.png)

Provide an appropriate resource name for your instance and then choose the **Developer (no SLA)** pricing tier.  As mentioned in part 1, there are some restrictions placed on the consumption tier so for a real world application you would probably want to use one of the other tiers, and for this example we need access to the management API that you don't get with the consumption tier.

![Create Service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gvuva4zlpdhvdf014gn.png)

All other settings can be left at their default values for this example.  The creation process may take a little bit of time.

## Import Functions

Once your API Management resource has created open it in Azure and choose **APIs** from the left menu and then **Function App**

![Import Function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zrzwpl8rg8ie9j1zf4oc.png)

In the import wizard that opens you should be able to browse to your Function and Select the calls you want to import.

![Import APIs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/154c3bwicxquq0vea8wi.png)

Your import for the System function should look similar to this.

![Import System](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68w374s997zw7e7ymdj4.png)

In my example I've used the 'Full' option and adjusted the 'API URL suffix' and included a 'Version identifier' to make the URL for this function a bit cleaner.

Do the same for the User function.

If we open the v1 User API and click on the **Test** tab you should be able to see the complete **Request URL**.

![GetUserData Function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6yqot48ioepujdcp67v.png)

Lets head back to Postman and try calling this API, but this time **don't** add the **x-functions-key** header value.

![API Management Postman call](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhqv8reyx5siyc8priv1.png)

Notice that we received a slightly different error message this time.  If we head back to the Function and look at the **App keys** you'll see that API Management has automatically created it's own **Host key**, apim-DevToAPIMan, and automatically uses this to call the function.

![API Management Host Key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtns9mguevy7716dnyca.png)

The API Management URI is now protected by a subscription key that can be generated in the API Management interface and we're going to use this alongside **Products** to provide us with a lot of control when it comes to providing access to our APIs.

Add two new products via the left hand menu option in API Management, one for the system function and one for the user function.  Give them appropriate names and then also choose the APIs you want this product to give access to, ticking the 'Published' checkbox along the way.

![Create Product](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zfrpri48chxs8m6dcmr.png)

Being able to specify which APIs are included in a product allows us to create separate products for different user types, with access to only the APIs those types require if we want.

Once we've created the products head over to the **Subscriptions** left hand menu entry and add a new subscription. 

![Create Subscription](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7w6cyfspfl2phx0lq9gd.png)

You'll notice in the create subscription screen we can set the scope **Product** and then select the product that this subscription has access to.

When the subscription is created two keys are generated for us, a primary and a secondary.  This could allow us to, for example, use the primary key internally in our application to call services as a user, but then make the secondary key visible to the user so that they can call the APIs themselves, this way we can differentiate between an internal application call and an external user call at runtime, and also revoke and regenerate one or both of the keys as required.

![Subscription Keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8lfc7rxiyz0u116nvs3g.png)

Before we go ahead and use these keys, head back to our APIs and in the settings change the header and query parameter names to something easier, in this example 'devto-key'.

![Subscription setting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abcd3b02scl63lj6kocr.png)

With 'Subscription required' ticked if we now provide one of the primary or secondary keys via a header or query parameter called 'devto-key' we should gain access to our API call.

Let's give it a test.

![User API Management call](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxor1x283vzxc8fgggjh.png)

## Next Steps

We've now got Azure Functions which we've published that can be called directly if we include a host key, but we won't use that method for access, instead we've created an instance of Azure API Management, imported our functions and then used products and subscriptions to control access to the APIs.

In the final step we're going to bring this all together by making changes to our System Azure Function so that it can programmatically create new user subscriptions in our API Management instance. 

Head on over to Part 3 to continue this.

Pete

[![Buy Me A Coffee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whmy70aj858tvqekv5n7.png)](https://www.buymeacoffee.com/panachesoftware)