If there is one popular theme regarding API management, it’s gotta be the subject of facilitating technically partner access via Azure AD. This can be as simple as creating a single app registration to designing full governance model with scopes & roles, and chained App Registrations.

As always, if you want to generally know what is Azure API management, or what is Azure Active Directory, then check the following articles:
- https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-whatis
- https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts
- https://tools.ietf.org/html/rfc6749
Architecture

- The architecture with new app endpoints enables same app registration to provide native and confidential client access with different settings
- Scopes are defined per each partner registration
Create Centralized API Management Proxy SPN

- Here we want to create single-tenant app in order to be able to control roles and authorizations within our tenant for B2B accounts. In multi-tenant scenario this is possible too, but requires that you control most of the authorizations in another management plane, or in scopes only
- For redirect URI we input nothing, because this application will only act as Service Principal “Front” for the actual app registrations consuming API management
- We will use the FQDN of API management as displayName and AppID URL, in later calls we will use this as ‘Audience /Resource for the partner clients”
Create Scopes and machine account role for the SPN


$apps = '{ "oauth2Permissions": [ { "adminConsentDescription": "Allow the application to access PartnerAPI-Colda on behalf of the signed-in user.", "adminConsentDisplayName": "Access PartnerAPI-Colda", "id": "bc388acd-37a3-4358-8839-c84b4add4b23", "isEnabled": true, "type": "User", "userConsentDescription": "Allow the application to access PartnerAPI-Colda on your behalf.", "userConsentDisplayName": "Access PartnerAPI-Colda", "value": "user_impersonation" }, { "adminConsentDescription": "Allow the application to access PartnerAPI-Colda on behalf of the signed-in user.", "adminConsentDisplayName": "Access PartnerAPI-Colda", "id": "40cfe68d-bef2-4a4b-8944-fc9766ba17d8", "isEnabled": true, "type": "User", "userConsentDescription": "Allow the application to access PartnerAPI-Colda on your behalf.", "userConsentDisplayName": "Access PartnerAPI-Colda", "value": "user_impersonation2" }, { "adminConsentDescription": "Allow the application to access PartnerAPI-Colda on behalf of the signed-in user as reader.", "adminConsentDisplayName": "Access PartnerAPI-Colda -reader", "id": "a1203e4c-54bf-4e92-bb61-73e1e347cf9d", "isEnabled": true, "type": "User", "userConsentDescription": "Allow the application to access PartnerAPI-Colda on your behalf as writer to the API.", "userConsentDisplayName": "Access PartnerAPI-Colda -reader", "value": "Reader" }, { "adminConsentDescription": "Allow the application to access PartnerAPI-Colda on behalf of the signed-in user as Writer.", "adminConsentDisplayName": "Access PartnerAPI-Colda -writer", "id": "b68e3e4f-7f45-497f-a815-6dc6ef46bbc8", "isEnabled": true, "type": "User", "userConsentDescription": "Allow the application to access PartnerAPI-Colda on your behalf as Writer.", "userConsentDisplayName": "Access PartnerAPI-Colda", "value": "Writer" }, { "adminConsentDescription": "Service Account user Scope", "adminConsentDisplayName": "Service Account App permissions", "id": "508b851a-7393-478a-89b0-f83d1dcc825b", "isEnabled": true, "type": "Admin", "userConsentDescription": "Allow the application to access PartnerAPI-Colda on your behalf as Writer.", "userConsentDisplayName": "Access PartnerAPI-Colda", "value": "Service_Accounts" } ] }' | ConvertFrom-Json foreach ( $app in ($apps.oauth2Permissions)) { $app.id =([system.guid]::NewGuid()).guid } $apps |ConvertTo-Json -Depth 3 #Roles $apps ='{ "appRoles": [ { "allowedMemberTypes": [ "application" ], "displayName": "ReadOnly-ServiceAccount", "id": "03b62322-1913-4c61-86a7-c325ebd5925f", "isEnabled": true, "description": "ReadOnly-ServiceAccount only to read data.", "value": "ReadOnly-ServiceAccount" }, { "allowedMemberTypes": [ "application" ], "displayName": "ServiceAccounts", "id": "a59b7301-039e-4782-ad1f-fc443cce1786", "isEnabled": true, "description": "Machine 2 Machine -type integrations.", "value": "ServiceAccount" } ] }' | ConvertFrom-Json foreach ( $app in ($apps.appRoles)) { $app.id =([system.guid]::NewGuid()).guid } $apps |ConvertTo-Json -Depth 3
Create first partner application
- The first partner application is for typical use scenario of Client-Credentials Flow and Authorization Code Flow





Configure JWT validation for Partner Application

- Note how we don’t need to reference the Proxy SPN at all? That’s because in previous step we’ve configured permissions for the Partner API to consume the Proxy SPN of API Management, and we need to reference the correct audience only
- Also its recommended to validate clientID
Test the API as a Partner using Code Authorization Flow

- Response is what you would expect for Echo API’s create with POST-Verb

- For PartnerClientID, we use the AppID we created in the previous step
- We are using the public client redirect-uri to return the token for the user

Test the API as a Partner using Client Credentials Flow

- Response is what you would expect for Echo API’s create with POST-Verb

Thats it for now! I will provide more insights, how to use multi-tenant apps, and how transform scopes into correlating back-end calls in the next blog
0 comments on “Azure API Management – JWT validation for multiple Azure AD partner registrations”