Validate access tokens from multiple identity providers on Azure API Management
Azure API Management empowers you to expose, manage, and safeguard your APIs effortlessly. Discover the true potential of this robust service as we dive into configuring its policy capabilities. In this article, we will unveil the secrets of leveraging Azure API Management policies to validate access tokens from various identity providers and seamlessly handle authorization using scopes.
Whether you’re a seasoned developer or just starting your API journey, this article has something for everyone. We’ll guide you through a simple yet impactful use case that showcases the incredible versatility of API management policies. As you follow along, you’ll witness how the available syntaxes and features within policies can transform your request and response processing, making it more powerful and efficient.
While we explore a straightforward scenario, it’s essential to note that the potential of Azure API Management policies extends far beyond this. As your needs grow more complex, these policies offer structured solutions to address intricate use cases. Prepare to unleash the endless possibilities and take your API management game to new heights.
Join us on this exciting journey and unlock the full potential of Azure API Management policies. Get ready to elevate your API security, authentication, and authorization to new horizons.
Use Case Description
Our use case involves a single deployed API that exposes the following main resources:
GET /hotels
- Retrieves a list of hotels.POST /hotels
- Creates a new hotel.DELETE /hotels/{hotel-id}
- Deletes a hotel.
We will use two identity providers in our example:
- Auth0 — The requests passing the token from Auth0 will have permissions only to retrieve the result of
GET /hotels
. Requests toPOST
andDELETE
with the same tokens will receive a403 Forbidden
response. - Azure AD — The caller using Azure AD as the identity provider can use all three methods (
GET
,POST
,DELETE
).
We will use scopes to manage authorization for the API endpoints.
Prerequisites
Before we proceed, make sure you have the following:
- Access to the Azure Portal.
- An Azure API Management instance set up in your Azure account.
Step 1: Configure the API in Azure API Management
Let’s consider we have create our API Management instance with the name “hotelapi-test”
https://hotelapi-test.azure-api.net

We need to configure the API in Azure API Management. Follow these steps:
- Log in to the Azure Portal.
- Navigate to your Azure API Management instance.
- Select “APIs” from the left-hand menu.
- Click on the “Add API” button.
- Provide the necessary details for your API, such as the name, URL suffix, and subscription required settings.
- Save the changes.

Step 2: Add the API operations
Select the API created and click the button “Add operation”.
Enter the name of the operation (you can start with Add hotel), the method (POST) and the path (/hotels).
Repeat the process for the GET and the DELETE (including the url parameter {hotel-id} in the path field)
At the end you will have something like this:

Step 3: Configure Identity Providers
Next, let’s configure the identity providers. For this example, we will use Auth0 and Azure AD.
Configure Auth0
- Log in to your Auth0 account.
- Create a new API in Auth0 and note down the API identifier (audience) from the “Settings” tab.

- Configure the required permissions and scopes for the API endpoints. Go to the “Permissions” tab and configure the following scope:
read:hotels
- Grants permission to retrieve hotel data.
Remember to click on the “Add” button on the right side after having entered the scope details.

- In the “Machine to Machine applications” tab check that the application that has been created by default has the assigned scope and it is authorized to use the custom API. If not, click on the switcher and click on the checkbox related to the scope

- Get the client id and the client secret to be able to retrieve the token. For that, click “Applications” on the left menu of the Auth0 dashboard and choose the hotelapitest (Test Application) from the list

In the Basic information section you find the information about Client ID and Client Secret (unhide it clicking on the eye icon)

Configure Azure AD
- Create an Azure AD tenant: If you don’t already have an Azure AD tenant, create one by signing up for an Azure account and navigating to the Azure AD portal. Follow the instructions to create a new tenant.
- Register an application: Inside your Azure AD tenant, register an application that represents your API. Provide a meaningful name for the application

- Create the secret and the secretID for the application going to the “Certificate & Secrets” section and clicking “New client secret”

- Copy and note the secret somewhere because you will use it to retrieve the access token. Note also the Client ID for the application that is listed in the “Overview” section.

- Create the scopes for the application clicking “App roles” on the left menu and adding the following scopes clicking “Create app role”
read:hotels
write:hotels

Add the 2 roles.

- Now, always on the left menu click “API permissions” and then on “Add a permission”.
- On the right side panel that will open click on the “My Api” tab and choose the created API
- Choose the 2 permissions created before and click the blue button “Add permissions”

- The roles are now ready to be included in the token retrieved by the app
Step 4: Configure Azure API Management Policy
Now, let’s configure the Azure API Management policy to validate the access tokens from different identity providers, enforce the required permissions based on scopes, and manage authorization. Follow these steps:
- In the Azure Portal, navigate to your Azure API Management instance.
- Select the API you previously configured.
- Under the “API” section, click on the previously created APIs (Hotel API Test in our case), click “All operations” and select the small pencil icon close to the “Frontend” header in the APIdesigner interface.
- Replace the existing policy with the following policy:
<policies>
<inbound>
<base />
<set-variable name="token" value="@{
var authHeader = context.Request.Headers.GetValueOrDefault("Authorization", "");
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
{
return authHeader.Substring(7);
}
return null;
}" />
<set-variable name="iss" value="@(context.Variables.GetValueOrDefault("token", "").AsJwt()?.Claims["iss"]?.FirstOrDefault() ?? "")" />
<choose>
<when condition="@(context.Variables.GetValueOrDefault("iss", "").Equals("AUTH0_TENANT") && context.Request.Method.Equals("GET"))">
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" require-expiration-time="true">
<openid-config url="https://YOUR_AUTH0_DOMAIN/.well-known/openid-configuration" />
<audiences>
<audience>YOUR_AUTH0_API_IDENTIFIER</audience>
</audiences>
<required-claims>
<claim name="scope">
<value>read:hotels</value>
</claim>
</required-claims>
</validate-jwt>
</when>
<when condition="@(context.Variables.GetValueOrDefault("iss", "").Equals("https://sts.windows.net/<YOUR_AZURE_DIRECTORY_TENANT_ID>/"))">
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid." require-expiration-time="true">
<openid-config url="https://login.microsoftonline.com/YOUR_AZURE_AD_TENANT/.well-known/openid-configuration" />
<audiences>
<audience>YOUR_AZURE_AD_AUDIENCE</audience>
</audiences>
<required-claims>
<claim name="roles">
<value>read:hotels</value>
<value>write:hotels</value>
</claim>
</required-claims>
</validate-jwt>
</when>
<otherwise>
<return-response>
<set-status code="403" reason="Forbidden" />
</return-response>
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Make sure to replace the following placeholders:
YOUR_AUTH0_DOMAIN
with the domain of your Auth0 identity provider.YOUR_AUTH0_API_IDENTIFIER
with the identifier (audience) of your Auth0 API.YOUR_AZURE_AD_TENANT
with the domain of your Azure AD identity provider (your_tenant_name.onmicrosoft.com).YOUR_AZURE_AD_AUDIENCE
with the audience for the Azure AD provider in the format api://<APPLICATION_CLIENT_ID>.YOUR_AZURE_DIRECTORY_TENANT_ID
the UUID foundable under the Overview section of the App registration.
This policy includes conditional token validation based on the issuer claim (iss
) in the JWT token. It extracts the token from the Authorization header, get the issuer (placing it in a context variable used later) and it starts a conditional validation against the appropriate OpenID configuration URL and audience claim for each identity provider. It also checks for the presence of the required scopes (read:hotels
and write:hotels
) for authorization.
Specifically, for the Auth0 provider, it checks that the called method is GET (the only allowed) and the scopes contains the needed read:hotels
.
In case the use case was more complex we would probably need to split the policy
Step 5: Set Up Mock Responses
To simulate the behavior of the API endpoints and test the policy, we can set up mocks in Azure API Management. Follow these steps:
- In the Azure Portal, navigate to your Azure API Management instance.
- Select the API you previously configured.
Follow the instructions for the 3 API resources at:
- https://learn.microsoft.com/en-us/azure/api-management/mock-api-responses?tabs=azure-portal#add-an-operation-to-the-test-api
- https://learn.microsoft.com/en-us/azure/api-management/mock-api-responses?tabs=azure-portal#enable-response-mocking
configuring the following response bodies:
POST /hotels
HTTP code: 201
{
"id": "9slsdjd-iislz992033-AAJSKSz"
}
GET /hotels
HTTP code: 200
[
{
"id": "494932p-829298sjeh-l71clm2",
"name": "Hotel Savoy"
},
{
"id": "594932p-bp298sjeh-m72clml",
"name": "Hotel Rembrandt"
}
]
DELETE /hotels/{hotel-id}
HTTP code: 204
No body for this endpoint
Step 5: Demo the Final Result
Now, you can demo the final result by making requests to the API endpoints with tokens from different identity providers.
- Obtain an access token from Auth0
curl --request POST \
--url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
--header 'content-type: application/json' \
--data '{"client_id": "YOUR_AUTH0_API_IDENTIFIER", "client_secret": "YOUR_AUTH0_API_CLIENT_SECRET", "audience": "https://hotelapi-test.azure-api.net", "grant_type": "client_credentials"}'
- Obtain an access token from Azure AD
curl --request POST \
--url 'https://login.microsoftonline.com/402627e0-9f04-4571-aae1-32ab0d6e3556/oauth2/v2.0/token' \
-header ‘Content-Type: application/x-www-form-urlencoded' \
-data-urlencode 'grant_type=client_credentials' \
-data-urlencode 'client_id=<AZURE_AD_CLIENT_ID>’ \
-data-urlencode 'client_secret=<AZURE_AD_CLIENT_SECRET>' \
-data-urlencode 'scope=api://eeacfc8d-7a34–4934-b3bf-1d1878a75ffa/.default'
Send a GET /hotels, POST /hotels and DELETE/hotels/{hotel-id}
request to the API with the Azure AD token in the Authorization header.
- If the token is from Auth0 and has the
read:hotels
scope, you will receive the successful responses. - If the token is from your chosen identity provider and has the
read:hotels
scope, you should also receive a successful response.

Repeat the same with the Auth0 token in the Authorization header.
- For the GET /hotels, you will receive the correct response
- For the
POST /hotels and DELETE/hotels/{hotel-id}
you will get an error 403 Forbidden

By following these steps, you have successfully configured Azure API Management to validate access tokens from different identity providers, manage authorization using scopes, and enforce fine-grained access control for your API endpoints.
Conclusion
Azure API Management provides a comprehensive platform to secure and manage your APIs. By configuring the policy to validate access tokens from different identity providers, manage authorization using scopes, and enforce fine-grained access control, you can ensure that only authenticated and authorized requests are allowed to access your API resources. This enhances the security and control of your APIs, enabling you to meet the specific requirements of your use case.