API Management has the ability to validate a JSON Web Token (JWT) through the validate-jwt policy. If you use the OpenID config URI property in the policy and set it to your AAD tenant's OpenID Connect metadata document endpoint, the token would be validated for anyone in your tenant. The goal in this blog post is to control that access to only allow specific users, using an app registration, roles and claims. I will outline the steps to set this up below.
- Create an App registration in your Azure Active Directory.
Enter a name and Register, leave the other settings as they are for now.
- Open the App registration and go to the "App roles | Preview" blade. Create a role. For our purposes, we can use:
- Go to the "Expose an API" blade and set the Application ID URI:
- Now, try to get a token for this resource using Azure CLI:
az login
az account get-access-token --resource api://a268af9e-1598-4ec3-ad16-77e30b042f92 - Notice you will get a HTTP 400 error that states that Azure CLI is not an authorized client application. To fix this, go back to the "Expose an API" blade in the app registration and add a scope:
- Now, we can add the client application from the same blade. Use the client ID for Azure CLI from the error message on step 5. The error looks like this: "Get Token request returned http error: 400 and server response: {"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID '04b07795-8ddb-461a-bbee-02f9e1bf7b46' named 'Microsoft Azure CLI'."
- Next, we need to grant a user that role to test. Go to the "Overview" blade in your app registration and copy the Application (Client) ID. Then go back to Azure Active Directory, "Enterprise applications" blade and search for the Application ID. Open the enterprise application corresponding to your App registration.
- From the "Users and groups" blade, add yourself as a user and select the role you created on step 2:
- Now we can try to generate a token from Azure CLI again:
az account get-access-token --resource api://a268af9e-1598-4ec3-ad16-77e30b042f92' - Copy that token and decode it using https://jwt.ms:
- Go to API Management and create an API. We can use Http Bin to test:
- Create an operation:
- Edit the policy for the operation we created:
- The policy would look something like this:
<policies> <inbound> <validate-jwt header-name="Authorization" failed-validation-httpcode="403" failed-validation-error-message="Forbidden"> <openid-config url="https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/v2.0/.well-known/openid-configuration" /> <audiences> <audience>api://a268af9e-1598-4ec3-ad16-77e30b042f92</audience> </audiences> <issuers> <issuer>https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/</issuer> </issuers> <required-claims> <claim name="roles" match="any"> <value>APIM.Access</value> </claim> </required-claims> </validate-jwt> <base /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
Note: you can get the value for the OpenID config URL from the Azure Portal by going to Azure Active Directory -> App registrations -> Endpoints -> OpenID Connect metadata document
Note 2: The audience is the Application ID URI from Step 3.
Note 3: The value of the "roles" claim is the value of the role we created at Step 2.
Note 4: I added the issuer from the token I got from Azure CLI as well (you can see the value if you decode it - Step 10). - Now, let's test it using Postman. Generate another token using Azure CLI if the previous one expired (Step 9). Select your API Management operation in the Azure Portal and go to the Test tab to get the Request URL and your subscription key:
- Open postman and fill in the token in the Authorization header (including "Bearer " in front of the value), the subscription key if it's required, then send a request:
If you get a HTTP 403 and/or you need to debug, the OCP trace feature would be helpful. If you include the subscription key and the Ocp-Apim-Trace: true header, the response will contain a link to a trace file in the header Ocp-Apim-Trace-Location which will show what is going wrong.
For more information, these links would come in handy:
https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-restrict-your-app-to-a-set-of-users
https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps