Challenge:
I recently helped a customer setting up OAuth 2.0 with Azure AD to protect their API backend in Azure API Management. This Azure Doc has 90% of the content to help you set up everything you need but it lacked setting up client application like Postman to test APIs using Client Credentials flow.
Again, use this Azure Doc go through step 1 through 6 to complete the entire set up. If you are not interested in setting up APIM Developer Portal as Client Application, you can skip step 2, 3, 4 & 5 and follow steps below.
Solution:
Purpose of this blog is to go through how to protect your APIs published through Azure API Management using OAuth 2.0 Client Credential Flow and test using Postman. For completeness' sake and to avoid going back and forth I'm including some of the steps from this Azure Doc in this blog.
High level steps:
- Step 1: Register an application in Azure AD to represent the API
- Step 2: Register another application in Azure AD to represent a client application
- Step 3: Grant permissions in Azure AD
- Step 4: Configure a JWT validation policy to pre-authorize requests
- Step 5: Request JWT token using Postman
- Step 6: Inspect the token (optional step)
- Step 7: Make the API call
- Step 8: Build an application to call the API
Step 1: Register an application in Azure AD to represent the API
- In your Azure Portal, go to Azure Active Directory, select App Registrations
- Select New registration
- When the Register an application page appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, such as backend-app.
- In the Supported account types section, select an option that suits your scenario.
- Leave the Redirect URI section empty.
- Select Register to create the application.
- On the app Overview page, find the Application (client) ID value and record it for later.
- Under the Manage section of the side menu, select Expose an API and set the Application ID URI with the default value. Record this value for later.
- Under the Manage section of the side menu, select App roles then click Create app role:
- In the Display name, enter a meaningful role name for example: AddRole
- Allowed member types: select Applications
- Value: example: AddRole
- Description: <as necessary>
- Click Apply
- Repeat steps 8 to add necessary App roles supported by your API.
Step 2: Register another application in Azure AD to represent a client application
Register every client application that calls the API as an application in Azure AD. In this example, the client application is Postman that we will be using to test APIs.
To register another application in Azure AD to represent Postman:
- In your Azure Portal, go to Azure Active Directory, select App Registrations.
- Select New registration.
- When the Register an application page appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, such as client-app.
- In the Supported account types section, select Accounts in this organizational directory only (<tenant name> only - Single tenant).
- In the Redirect URI section, select Web and leave the URL field empty.
- Select Register to create the application.
- On the app Overview page, find the Application (client) ID value and record it for later.
- Create a client secret for this application to use in a subsequent step.
- Under the Manage section of the side menu, select Certificates & secrets.
- Under Client secrets, select New client secret.
- Under Add a client secret, provide a Description and choose when the key should expire.
- Select Add.
- When the secret is created, note the key value for use in a subsequent step (Note: you can't see/copy this value once you move away from this page, but you can create New Client Secret as needed)
- Repeat this step to register additional clients/customers (if any) who will be consuming your API
Step 3: Grant permissions in Azure AD
Now that you have registered two applications to represent the API and the Postman client app, grant permissions to
allow the client-app (Postman) to call the backend-app (API).
- In your Azure Portal, go to Azure Active Directory, select App Registrations.
- Choose your client app. Under the Manage section of the side menu, select API permissions.
- Select Add a Permission.
- Under Select an API, select My APIs, and then find and select your backend-app.
- Select Application permissions, then select the appropriate role (for example: AddRole) of your backend-app.
- Select Add permissions.
- Select Grant admin consent for <your-tenant-name>. Select Yes, if you get green tick mark under Status with message Granted for <tenant name> then you are all set, then move to next step 4.
- If you are not an Azure AD Global Admin, you can't provide this admin consent. If you are the API App owner (in this case you are because we set up the API App in Step1), then you may be able to use the following method to provide Admin consent using Graph Explorer.
- Go to Graph Explorer (make sure to change the tenant's name in the URL)
For example: https://developer.microsoft.com/en-us/graph/graph-explorer?tenant=<tenantname>.onmicrosoft.com - Sign in to Graph Explorer
- In the Search Sample queries enter: appRoleAssignment
- Select POST assign an appRoleAssignment to a serviceprincipal
- Click on Modify permissions (Preview) tab and consent Permission to AppRoleAssignment.ReadWrite.All, Directory.AccessAsUser.All & Directory.ReadWrite.All
- principalId = Client App's Object ID
- resourceId = API App's Object ID
- appRoleId = Id of App Role (in this example AddRole that we created in Step 1, you can get it using Portal)
- To get Client/API app's Object ID/ServicePrincipal Id, use CLI or PowerShell command (you can' t get from Azure Portal)
Using CLI: az ad sp list --display-name <Azure AD App Name>
Capture objectId where objectType = ServicePrincipal
-
In the POST URL, make sure to change {id}, this is same as resourceId from above (i.e., API App's Object ID)
https://graph.microsoft.com/v1.0/servicePrincipals/{id}/appRoleAssignments -
Run query. If all goes well and you got all the right Ids, you should get Created - 201 response as shown below. Check the API permission again to make sure you got the green tick mark under Status with message Granted for <tenant name>
Step 4: Configure a JWT validation policy to pre-authorize requests
Follow the instruction from the following doc to add Validate JWT policy to your API
Protect API backend in API Management using OAuth 2.0 and Azure Active Directory - Azure API Management | Microsoft Docs
Add the following Validate JWT policy to <inbound> policy section of your API which checks the value of the audience claim in an access token obtained from Azure AD, and returns an error message if the token is not valid.
- Update aad-tenant value
- Update aud claim value which is our API App's Application (client) ID which we created in Step1
- You can also validate additional claims that the token will have, in our case we added App Roles called AddRole in Step 1 (see example below)
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{aad-tenant}/v2.0/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>{backend-api-application-client-id}</value>
</claim>
</required-claims>
</validate-jwt>
For example, to include additional claim:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/azurerampup.onmicrosoft.com/v2.0/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>3b0bd75a-d72f-46ec-99f1-040bab17d0ed</value>
</claim>
<claim name="roles" match="all">
<value>AddRole</value>
</claim>
</required-claims>
</validate-jwt>
Step 5: Request JWT token using Postman
Now that all the setup is over, let's get JWT token first, before we make API calls
- Go to Postman, create POST request with following values:
- URL: Go to your Client App in Azure AD, click Endpoints, copy OAuth 2.0 token endpoint (v2) URL
- Select Body then x-www-form-urlencoded
- Enter following values
KEY |
VALUE |
grant_type |
client_credentials |
client_id |
Your client App's (step 2 from above) Application (client) ID, you can copy from Portal |
client_secret |
Your client App's client secret |
scope |
<your API app's Application (client) ID>/.default |
e. Send the request, if all goes well you should get the JWT token as shown below.
Step 6: Inspect the token (optional step)
- Go to: https://jwt.ms
- Copy the JWT token from previous step and paste, it will decode the token
- It will include the roles (for example: roles: "AddRole")
- This proves that Postman (client) got the token which has permission to AddRole
Step 7: Make the API call
Time to call our APIs using Postman with JWT token that we got from step 5.
- Go to Postman, create Get/POST request based on your API operation
- Select Headers and enter the following values:
KEY |
VALUE |
Ocp-Apim-Subscription-Key |
Subscription key from APIM |
Authorization |
Bearer <JWT token from step 5> |
- Click Send, if all goes well APIM should validate the JWT token, make backend API call and return the response
Step 8: Build an application to call the API
In this blog we used Postman to test API calls, but in Production you or your customers would build an application and implement OAuth 2.0, see Azure AD code samples.