Azure API Management policies are the XML bouncers between your consumers and your backend APIs. Designed well, they validate tokens, smooth traffic spikes, keep browser clients honest and keep secrets out of reach. Designed casually, they turn APIM into an expensive request-forwarding service.
Here are seven practical guardrails. They don’t replace backend security; they make the gateway do gateway work well so your apps can focus on business logic.
Where Azure API Management policies fit
Policies run in the gateway, in four sections:
- Inbound: validate, normalize, throttle, route and authenticate before the backend sees the request.
- Backend: behavior while forwarding.
- Outbound: shape the response before it returns.
- On-error: controlled handling of gateway errors.
API policy flow
App, user or service
JWT, CORS, throttle
Route and auth
App, function or service
Policies change runtime behavior without rebuilding backends. That’s the power, and the risk: a broad global policy affects every API.
1. Preserve inherited policies with <base />
Policies apply at global, workspace, product, API and operation scope. Microsoft recommends a <base /> element at the start of each section so child scopes inherit parent policies. Without it, an operation-level edit can silently bypass a global control.
<policies>
<inbound>
<base />
<!-- Operation-specific policies go here -->
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
If an API seems to ignore a policy, check the effective policy view in the portal to confirm inheritance isn’t skipped.
2. Validate tokens before the backend works
validate-jwt enforces a valid JWT from a header, query parameter or token value; for Entra tokens, validate-azure-ad-token is purpose-built. Reject bad identity signals early, checking issuer, audience, expiry, required claims and the Bearer scheme:
<validate-jwt header-name="Authorization"
require-scheme="Bearer"
failed-validation-httpcode="401"
failed-validation-error-message="Invalid or missing access token">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>api://your-api-app-id</audience>
</audiences>
<issuers>
<issuer>https://login.microsoftonline.com/{tenant-id}/v2.0</issuer>
</issuers>
</validate-jwt>
Gateway validation doesn’t replace authorization in the API. Object-level checks belong in the backend, which understands the business object. For 401 troubleshooting, see Azure API Management JWT validation.
3. Rate-limit by the right key
rate-limit-by-key limits calls per key over a renewal period and returns 429 Too Many Requests when exceeded. The design choice is the key:
| Counter key | Good for | Watch out for |
|---|---|---|
context.Request.IpAddress | Public or anonymous APIs, quick abuse controls | NAT can make many users look like one caller. |
| Subscription ID | Developer portal and product-based APIs | Only useful where subscription keys are part of the design. |
| JWT claim | Per-app, per-user or per-tenant limits | Validate the token before trusting its claims. |
<rate-limit-by-key calls="120"
renewal-period="60"
counter-key="@(context.Request.IpAddress)"
remaining-calls-header-name="x-ratelimit-remaining"
retry-after-header-name="Retry-After" />
Microsoft notes throttling is distributed and not perfectly precise, so treat it as an operational control, not a billing meter. Choose the control to match the goal: rate limits for short spikes, quotas for longer-term allowances, and concurrency limits for fragile backends.
4. Make CORS intentionally boring
The cors policy handles cross-origin browser access at the gateway. Microsoft’s reference flags common issues: policy order, header-based subscription keys at product scope, and overly permissive wildcards.
- Place
corsearly in the inbound section. - Avoid
*unless the API really serves any origin. - List explicit origins, and only the methods and headers clients need.
- Test preflight (OPTIONS) requests separately.
<cors allow-credentials="false" terminate-unmatched-request="true">
<allowed-origins>
<origin>https://apps.contoso.com</origin>
</allowed-origins>
<allowed-methods preflight-result-max-age="300">
<method>GET</method>
<method>POST</method>
</allowed-methods>
<allowed-headers>
<header>authorization</header>
<header>content-type</header>
</allowed-headers>
</cors>
5. Use managed identity carefully
authentication-managed-identity gets an Entra token for a target resource and sets it as a Bearer token, removing hardcoded secrets from gateway-to-backend calls. Microsoft warns that users who can edit policies may misuse the token if permissions and scopes are too broad.
<authentication-managed-identity resource="https://vault.azure.net" />
- Grant the identity only the permissions the backend call needs.
- Prefer API or operation scope over global when one API needs the token.
- Review who can edit policies, not just who deploys APIs.
- Use backend entities and routing so tokens only reach trusted services.
See Azure API Management managed identity troubleshooting for when the permissions, network path or scope are slightly wrong.
6. Add response headers on purpose
set-header adds, overrides, appends or deletes headers. Useful candidates: x-correlation-id for support tickets, version or deprecation hints during migrations, security headers for browser-facing APIs, and remaining-call headers so clients back off before a 429.
<set-header name="x-gateway-region" exists-action="override">
<value>@(context.Deployment.Region)</value>
</set-header>
Some headers, including Connection, Content-Length, Keep-Alive and Transfer-Encoding, can’t be overridden, appended or deleted.
7. Build a troubleshooting checklist before the outage
- Confirm the effective policy includes parent controls.
- Validate JWT issuer, audience and required claims.
- Test CORS preflight separately.
- Check the rate-limit counter key and scope.
- Review managed identity permissions and policy edit rights.
- Use correlation headers and logs for repeatable support.
API policies protect runtime behavior; Azure Resource Graph queries catch configuration drift across the estate.
A baseline Azure API Management policies pattern
A simplified pattern combining inheritance, CORS, token validation, rate limiting and a header. Adapt the values to your tenant and clients.
<policies>
<inbound>
<base />
<cors allow-credentials="false" terminate-unmatched-request="true">
<allowed-origins>
<origin>https://apps.contoso.com</origin>
</allowed-origins>
<allowed-methods preflight-result-max-age="300">
<method>GET</method>
<method>POST</method>
</allowed-methods>
<allowed-headers>
<header>authorization</header>
<header>content-type</header>
</allowed-headers>
</cors>
<validate-jwt header-name="Authorization"
require-scheme="Bearer"
failed-validation-httpcode="401">
<openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>api://your-api-app-id</audience>
</audiences>
</validate-jwt>
<rate-limit-by-key calls="120"
renewal-period="60"
counter-key="@(context.Request.IpAddress)"
remaining-calls-header-name="x-ratelimit-remaining" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<set-header name="x-gateway-region" exists-action="override">
<value>@(context.Deployment.Region)</value>
</set-header>
</outbound>
<on-error>
<base />
</on-error>
</policies>
Safe rollout
- Inventory global, product, API and operation policies.
- Stage changes on a non-production API or test operation.
- Validate auth, CORS, throttling and routing with real client patterns.
- Deploy narrowly, then widen scope once proven.
- Monitor 401, 403, 429 and backend error trends afterwards.
Last reviewed: October 2026
Sources
- Policies in Azure API Management (Microsoft Learn)
- validate-jwt policy (Microsoft Learn)
- rate-limit-by-key policy (Microsoft Learn)
- cors policy (Microsoft Learn)
- authentication-managed-identity policy (Microsoft Learn)
- set-header policy (Microsoft Learn)
- Mitigate OWASP API threats with API Management (Microsoft Learn)
Discover more from Cloud Osprey
Subscribe to get the latest posts sent to your email.