| page_type | languages | name | description | products | urlFragment | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sample | 
 | Using Managed Identity to Authenticate Azure Functions and APIM | The sample includes examples of how to authenticate from Azure Functions to Azure API Management and from Azure API Management to Azure Functions using Managed Identities. | 
 | functions-apim-managed-identity | 
This is example code showing how to authenticate from Azure Functions to Azure API Management (APIM) and from Azure API Management to Azure Functions using a managed identity.
| File/folder | Description | 
|---|---|
| src | Azure Function C# Code | 
| terraform | Terraform IAC Code | 
| .gitignore | Define what to ignore at commit time. | 
| CHANGELOG.md | List of changes to the sample. | 
| CONTRIBUTING.md | Guidelines for contributing to the sample. | 
| README.md | This README file. | 
| LICENSE.md | The license for the sample. | 
This example covers the following use cases:
- Azure Function App to Azure API Management authentication using a Managed Identity.
- Azure API Management to Azure Function App authentication using a Managed Identity.
There are currently some limitations when using Managed Identity for these use cases that you should be aware of:
- 
Access Tokens are cached for 24 hours and there is no way to override this. This means that any changes you make to your App Registration with regards to app roles, claims, etc will not be available in the token generated from the MSI enabled app for up to 24 hours. This can be quite problematic when developing, but should not have a significant impact on production workloads. More details on this limitation can be found here and here. HINT: When developing with Terraform, you can just delete your Managed Identity and let Terraform re-create it to refresh your token. 
- 
Managed Identities (any Service Principal) cannot be assigned to an App Registration App Role via an AzureAD Group. This is a major limitation for customers that want to use groups across the board, but it does not mean you can't use Managed Identities. It simply means you have assign the Managed Identity directly the the App Registration App Role. More details on this limitation can be found here. Specifically the sentence Currently, if you add a service principal to a group, and then assign an app role to that group, Azure AD doesn't add the roles claim to tokens it issues..
- The Azure Functions Core Tools CLI: Download
- HashiCorp Terraform CLI: Download
- Azure CLI: Download
- An Azure Subscription: Free Account
- Clone this repository to your local machine
We deploy the infrastructure using Terraform first. Follow these steps to login to Azure and apply the Terraform.
- Open your console of choice and navigate to the the /terraformfolder.
- Run az loginto login to your Azure Account.
- Run az account set --subscription [my-subscription]where [my-subscription] is the name of your subscription.
- Run terraform initto pull down the providers.
- Run terraform apply. Take a look at the plan it generates and then typeyesto run the plan.
- The function code is deployed as part of the Terraform using a local provisioner which runs the func azure functionapp publishcommand of the Azure Functions Core Tools CLI.
- Take note of the outputs from Terraform as you'll need these later.
- Take a look at the resource groups and resources in the Azure portal.
Each use case has it's own demo as follows:
This following diagram provides an overview of the demo for this use case:

For the Function App to APIM authentication use case, the most important parts can be found in these files:
The Azure Function code follows these steps:
- Get the user assigned managed identity.
- Generate a JWT from the user assigned managed identity, passing in the App Registration scope in the case of the groupexample.
- Make a call to the APIM end point, passing the JWT in the Authorization Bearer header.
There are two different examples of the APIM Policy:
The simple function does not use an App Registration and generates a generic JWT for itself:
- It uses the validate-azure-ad-tokenpolicy type.
- It specifies that only the client ID of the user assigned managed identity for the trusted public function app can access the operation. It does this by including it in the client-application-idslist.
The group function uses an App Registration so it can be assigned an App Role and pass that claim to APIM:
- It uses the validate-jwtpolicy type.
- It specifies that only the App Registration audience is valid. It does this by including it in the audienceslist.
- It specifies that only the App Role claim assigned to the Managed Identity is valid. It does this by including it in the required-claimslist.
To run the demo, follow these steps:
- Simple Untrusted: Navigate to the untrusted function app, using the url in public_untrusted_simple_demo_url. You should see a 401 error like this:{ "statusCode": 401, "message": "Invalid Azure AD JWT" }.
- Simple Trusted: Navigate to the trusted function app, using the url in public_trusted_simple_demo_url. You should see a successful call like this:{"message":"Hello from the Private Function! The APIM Managed Identity has been assigned to the role: Private.Example","dateOfMessage":"2022-11-08T12:14:59.4735675+00:00"}.
- Group Untrusted: Navigate to the untrusted function app, using the url in public_untrusted_group_demo_url. You should see a 401 error like this:{ "statusCode": 401, "message": "Unauthorized. Access token is missing or invalid." }.
- Group Trusted: Navigate to the trusted function app, using the url in public_trusted_group_demo_url. You should see a successful call like this: `{"message":"Hello from the Private Function! The APIM Managed Identity has been assigned to the role: Private.Example","dateOfMessage":"2022-11-08T12:14:59.4735675+00:00"}
As you can see the untrusted function does not have it's managed identity specified in the APIM policy, so it is not authenticated. More details on the policy can be found here.
This following diagram provides an overview of the demo for this use case:

For the APIM to Function App authentication use case, the most important parts can be found in these files:
- APIM Policy definition: apim.tf
- Azure Function Authentication Configuration: function_private.tf
- AzureAD App Registration: azuread_applications.tf
The APIM Policy includes the following steps:
- It uses the authentication-managed-identitypolicy to retrieve the JWT to authenticate. It specified the client ID of the App Registration in theresourceattribute and the client ID of the user assigned managed identity in theclient-idattribute.
- It takes the output of the previous step and adds the JWT to the Authorization Bearer header using the set-headerpolicy.
The AzureAD App Registration has the following attributes:
- It is configured using the instructions defined here in the documentation.
- It is configured to require users or groups to be assigned using the app_role_assignment_requiredproperty.
- It has the user assigned managed identity assigned to the default role.
- This combination of settings ensures that only the user assigned managed identity we specified has access to the Private Function.
The Private Function has the following attributes:
- It is configured to have AzureAD authentication enabled using the App Registration described in the previous section
- The enforces that only authenticated users / services can access the Function App.
To run the demo, follow these steps:
- Navigate to the trusted function app, using the url in public_trusted_demo_url.You should see a successful call like this:{"message":"Hello from the Private Function! The APIM Managed Identity has been assigned to the role: Private.Example","dateOfMessage":"2022-11-08T12:14:59.4735675+00:00"}.
- Open Azure Portal and navigate to your APIM instance.
- Open the APIssection and click on theUntrusted APIentry.
- Select the Test Operationand open theTesttab.
- Hit Sendand you will get a 500 error.
- Hit Trace, then navigate to the Trace and scroll down to theauthentication-managed-identitysection.
- You will see details of why a 500 error was produced and it is because the user assigned managed identity is not assigned to the App Registration.