Azure API Management with OAuth 2.0
Azure API Management with OAuth 2.0
Enabling OAuth2 in Azure API Management (APIM)
ensures that all external consumers authenticate using a secure,
industry-standard token-based model, regardless of how the backend systems
(e.g., website, mobile apps, SaaS APIs) handle authentication. This creates a
centralized security layer that abstracts backend differences, enforces
consistent access control, supports fine-grained authorization (via
scopes/claims), and provides detailed auditing and monitoring for compliance.
In short, it improves security, governance, and partner onboarding while
simplifying backend integration.

In an OAuth2-enabled Azure API Management
(APIM) setup, a client app first requests an access token from an Identity
Provider (such as Azure AD), which validates the credentials and issues an
access token (and possibly a refresh token). The client then sends its API
request to APIM, including the token in the authorization header. APIM
validates the token by checking its signature, claims, issuer, audience, and
expiry against the Identity Provider. If the token is expired, APIM can use the
refresh token to request a new one. Once the token is validated, APIM enforces
policies such as throttling, logging, or data transformation before forwarding
the request to the backend API. Depending on the backend’ s requirements, APIM
can pass the client’s token directly or perform a token exchange to provide a
different credential format. The backend API then processes the request and
returns the response to APIM, which in turn delivers it back to the client.
This flow ensures secure, controlled, and policy-driven access to backend
services while centralizing authentication and authorization in APIM.

Create APIM Instance:
For this Demo I’m using APIM developer version
which support Azure AD Integration. This is a prerequisite to enable Azure APIM
with oAuth2.0

Once your
APIM has been created, Add API >> click Add API and select HTTP (manual
define an HTTP API) like below settings:

Create TWO API endpoints:
-
PO
Confirmation: Accessible to Vendor A
-
Payment
confirmation: Accessible to Vendor B
Now you can
add operation, this will create final API endpoint to test. Click Add operation
>>

Click save
to create endpoint. Now its time to configure inbound policy.
Which
should look like:
<inbound>
<base />
<return-response>
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>
{
"po":
"12345",
"name":
"Sangita Shaw",
"status":
"active"
}
</set-body>
</return-response>
Now test
your API from APIM Portal itself. Click on the test tab, select the product and
send it. The request and response should look like this:

Let’s
create Payment confirmation API endpoint. Same like previous steps, app
operation and name it “Mock Payment”

After
adding the API, click on plus sign of Add policy and select “mock response”
with default values.
The inbound
policy should look like:
<inbound>
<base />
<mock-response status-code="200"
content-type="application/json" />
</inbound>

Now Once
again, sent Frontend edit but and click on response tab. Add response.

And Save.
Now it’s time to test.

So far so
good, both endpoint works fine. You can test them from postman as well only one
extra setting to provide i.e. subscription key in the postman. Like:
|
|
|
The sequent
steps are actually involved to enable your API endpoints with oAuth2.0.
App Registration
We are
going to add 2 separate applications pointing to each Api endpoints and one
more app for accessing backend process.
App1 Name: APIMResourcePO
App2 Name: APIMResourcePay
App3 Name: APIMVendorAccess
Except the
names all other steps are identical for App1 & 2.
Step 1: Create an app with name
“APIMResourcePO” with all default values.

Step 2: Select menu item “Expose an API” from
the left panel and then click “Application ID UR”. Press save with default
value.

Note the “Application
ID URI” for app APIMResourcePO
in configuration table below. We need this later.
Step 3: Select menu item “App roles” from
the left panel and then click “Create app role” from top left. Press save with display
name “readerPO” and value “ReaderPO”.

Step 4: Select menu item “Manifest” from
the left panel and then Open 2nd tab “AAD Graph App Manifest
(Deprecating Soon)” and Change the “accessTokenAcceptedVersion” value null to
2. Save it.

Repeat the
same steps for app registration of “APIMResourcePay”.
Let’s
create 3rd app with name “APIMVendorAccess” and configure it.
Step 1: Create app with default values.
Once its create get the client ID, tenant ID from overview menu option.
|
|
|
Step 2: Select menu item “Certificates
& secrets” from the left panel and then click “New client secrets” Plus
button. Caution save the secret it won’t visitable again.

Step 3: Assign
permission to this app
Select the ‘API permissions’ menu option from left panel and Add
a permission. This step is a bit tricky since you should have the privilege to grant
consents; otherwise, approach to your Azure Admin to “Grant Admin consent”, after
you configure this step.
Action1: Add permission to the role we defined for
other 2 apps inthe previous steps (2 app we registered in previous steps..)


Action2: Add permission to Graph API for read &
readAll (real all might be missing).


Action3: Grant Admin consent to the permissions. If
the button is disabled, please check with your Azure Admins.

Once consent provided status would be green.

|
App registration Configuration |
Source |
|
|
APIMResourcePO
(App Scope) ID URI: |
api://8f0c359e-553d-470d-a8da-30b3db8953b7 |
App 1 |
|
APIMResourcePay
(App Scope) ID URI: |
api://9f99dfe2-dd41-45bf-8e3b-8f4efb85f6ad |
App
2 |
|
Client ID |
ab2d512d-2c18-4627-abd4-12a5dff8b5ac |
App 3 |
|
Tenant ID |
1daa2d13-d914-45ab-bd4f-1d5b11e7788d |
App
3 |
|
Secret |
WFy8Q~GRY5i~DN4ZIV1K.sA4CyJmQpYjwxXYeaaD |
App 3 |
Step 4: Select menu item “Manifest” from
the left panel and then Open 2nd tab “Microsoft Graph App Manifest
(New)” and Change the “requestedAccessTokenVersion” value null to 2. Save it.

APIM Policy Configuration
This is the
final step to do, open again your APIM and select the endpoint you want to
enable with oAuth2.
In this
case Select Mock Payment Get operation and App Policy (+ button). Select
“Validate JWT” inbound policy.
And do the
following configuration.
|
Key |
Value |
|
Header
name |
Authorization |
|
Failed validation HTTP code |
401 Unauthorized |
|
Failed
validation error message |
Access Token invalid |
|
Required claims -1 |
|
|
Name |
aud |
|
Match |
All Claims |
|
Values |
9f99dfe2-dd41-45bf-8e3b-8f4efb85f6ad (i.e. Scope of
APIMResourcePay) |
|
Required claims -2 |
|
|
Name |
iss |
|
Match |
All Claims |
|
Values |
https://login.microsoftonline.com/{{azTenantID}}/v2.0 https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d/v2.0 |
|
Open ID URLs |
https://login.microsoftonline.com/{{azTenantID}}/v2.0/.well-known/openid-configuration https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d
/v2.0/.well-known/openid-configuration |

You need to
put “validate jwt” policy before mock-response policy.
And
finally, your policy should look like:
|
<policies> <!-- Throttle, authorize,
validate, cache, or transform the requests --> <inbound> <base /> <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="DK::Access
Token is invalid"> <openid-config url="https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d
/v2.0/.well-known/openid-configuration" /> <required-claims>
<claim name="aud" match="all">
<value>9f99dfe2-dd41-45bf-8e3b-8f4efb85f6ad</value>
</claim>
<claim name="iss" match="all">
<value>https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d/v2.0</value>
</claim> </required-claims> </validate-jwt> <mock-response status-code="200" content-type="application/json" /> </inbound> <!-- Control if and how
the requests are forwarded to services --> <backend> <base /> </backend> <!-- Customize the
responses --> <outbound> <base /> </outbound> <!-- Handle exceptions
and customize error responses --> <on-error> <base /> </on-error> </policies> |
Note: you
can hide the values such as Tenant ID, App Scope and so on in the Named values
and access them as variable in the policy. This approach would reduce the
chance of typo errors.

And then
modify the inbound policy with assigning the variables.
|
<policies> <!-- Throttle, authorize,
validate, cache, or transform the requests --> <inbound> <base /> <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="DK::Access
Token is invalid"> <openid-config url="https://login.microsoftonline.com/{{azTenantID}}/v2.0/.well-known/openid-configuration" /> <required-claims>
<claim name="aud" match="all">
<value>{{appScopePay}}</value>
</claim>
<claim name="iss" match="all">
<value>https://login.microsoftonline.com/{{azTenantID}}/v2.0</value>
</claim> </required-claims> </validate-jwt> <mock-response status-code="200" content-type="application/json" /> </inbound> <!-- Control if and how
the requests are forwarded to services --> <backend> <base /> </backend> <!-- Customize the
responses --> <outbound> <base /> </outbound> <!-- Handle exceptions
and customize error responses --> <on-error> <base /> </on-error> </policies> |
Next
Configure Mock PO API endpoint.
The
Validate JWT token policty would be the identical except the scope should be
assign to “APIMResourcePO”
And the
policy should look like:
|
<policies> <!-- Throttle, authorize,
validate, cache, or transform the requests --> <inbound> <base /> <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="DK::Access
Token is invalid"> <openid-config url="https://login.microsoftonline.com/{{azTenantID}}/v2.0/.well-known/openid-configuration" /> <required-claims>
<claim name="aud" match="all">
<value>{{appScopePO}}</value>
</claim>
<claim name="iss" match="all">
<value>https://login.microsoftonline.com/{{azTenantID}}/v2.0</value>
</claim> </required-claims> </validate-jwt> <return-response> <set-status code="200" reason="OK" /> <set-header name="Content-Type" exists-action="override">
<value>application/json</value> </set-header> <set-body>{
"po": "12345",
"name": "Sangita Shaw",
"status": "active" }</set-body> </return-response> </inbound> <!-- Control if and how
the requests are forwarded to services --> <backend> <base /> </backend> <!-- Customize the
responses --> <outbound> <base /> </outbound> <!-- Handle exceptions
and customize error responses --> <on-error> <base /> </on-error> </policies> |
Test though Postman
Test Step1: Get the token for Payment
To get a
valid token using this curl:
curl --location 'https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d/oauth2/v2.0/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=ab2d512d-2c18-4627-abd4-12a5dff8b5ac' \
--data-urlencode 'client_secret=WFy8Q~GRY5i~DN4ZIV1K.sA4CyJmQpYjwxXYeaaD' \
--data-urlencode 'scope=api://9f99dfe2-dd41-45bf-8e3b-8f4efb85f6ad/.default'

Use this
token to invoke Payment api endpoint and you would get success response

Use this
same token to invoke PO api endpoint and you won’t get successful response

Test Step2: Get the token for PO
In order to
get valid token for PO (purchase order) change the scope while creating the jwt
token. And the curl should look like:
curl --location 'https://login.microsoftonline.com/1daa2d13-d914-45ab-bd4f-1d5b11e7788d/oauth2/v2.0/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=ab2d512d-2c18-4627-abd4-12a5dff8b5ac' \
--data-urlencode 'client_secret=WFy8Q~GRY5i~DN4ZIV1K.sA4CyJmQpYjwxXYeaaD' \
--data-urlencode 'scope=api://8f0c359e-553d-470d-a8da-30b3db8953b7/.default'

Use this
token to call PO api endpoint and you would get a success response.

And if you
use the same token to call payment api, the response wound be invalid.

Reference:
https://azure.microsoft.com/en-in/pricing/details/api-management/
https://learn.microsoft.com/en-us/azure/api-management/import-and-publish (https://learn.microsoft.com/en-us/azure/api-management/mock-api-responses)




Comments
Post a Comment