Integration Security & Governance
Every integration needs to answer two questions before it ships: “how does the other side prove who it is,” and “who’s watching for this contract quietly breaking someone downstream?”
At a glance
Section titled “At a glance”- What it is: The controls that keep cross-system integrations safe and well-behaved: OAuth2 client credentials (a system authenticates as itself, not as a user, to call another system), mTLS (mutual TLS — both sides present certificates to verify each other, not just the client verifying the server), rate limiting/throttling (capping how often a consumer can call an API), and contract governance (a process ensuring API/event changes don’t silently break existing consumers).
- Why it matters: An integration with no auth is an open door; one with no rate limit is one noisy consumer away from taking down a shared system; one with no contract governance is a breaking change away from silently failing every downstream consumer at once.
- For developers: before exposing or consuming any cross-system API, check it has machine-to-machine auth (not a shared static API key), a rate limit, and a documented deprecation policy — these are cheap to add early and expensive to retrofit after the first outage.
- When to use it: Every integration that crosses a system, team, or organizational boundary.
- When not to use it: N/A — some level of auth and rate limiting is appropriate for essentially every integration; the degree of governance formality can scale down for low-risk internal integrations.
- Prerequisites: API-Led Connectivity.
Mental model
Section titled “Mental model”graph LR
S[Order Service] -- OAuth2 client credentials + mTLS --> GW[API Gateway]
GW -- rate limit + auth check --> P[Partner Shipping API]
GW --> M[Monitoring / Contract Governance]
The gateway is the checkpoint: it verifies identity, enforces rate limits, and is the natural place to observe whether consumers are honoring the contract.
Step-by-step walkthrough
Section titled “Step-by-step walkthrough”- Choose a machine-to-machine auth method: OAuth2 client credentials for most API calls, mTLS in addition when the connection itself (not just the request) needs mutual verification (e.g. high-trust partner links).
- Configure rate limiting/throttling at the gateway per consumer, not just globally, so one noisy consumer can’t starve others.
- Version every contract (API or event schema) and communicate a deprecation window before removing an old version.
- Set up monitoring on the gateway/broker for auth failures, rate-limit rejections, and contract/schema validation errors.
- Establish a lightweight governance checkpoint (even just a peer review) for any breaking contract change before it ships.
Worked example
Section titled “Worked example”The internal Order service needs to call a partner’s Shipping API to schedule deliveries. The partner requires strong assurance of identity, and the internal platform team needs visibility into how much traffic the Order service is sending.
- Input: a planned direct call from Order service to the partner Shipping API with no agreed auth mechanism and no rate limiting.
- Process: the Order service authenticates using OAuth2 client credentials to get a short-lived token, and the connection itself uses mTLS so both sides present certificates. The call is routed through an API gateway that enforces a per-consumer rate limit and logs every call for monitoring dashboards. The Shipping API’s contract is versioned, and the partner commits to a deprecation window before retiring any version.
- Output: the integration has verifiable machine identity on both sides, protection against one runaway process overwhelming the partner, and a documented path for future contract changes instead of surprise breakage.
var app = ConfidentialClientApplicationBuilder.Create(clientId) .WithClientSecret(clientSecret) .WithAuthority(authority) .Build();
var token = await app.AcquireTokenForClient(new[] { "api://shipping-partner/.default" }) .ExecuteAsync(); // OAuth2 client credentials flow
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);Microsoft Entra ID issues the client-credentials token, and Azure API Management enforces the per-consumer rate limit and mTLS certificate check before the request reaches the partner.
resource apimPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-09-01' = { name: 'pe-apim-internal' location: location properties: { subnet: { id: subnetId } privateLinkServiceConnections: [ { name: 'apim-connection', properties: { privateLinkServiceId: apim.id, groupIds: ['Gateway'] } } ] }}The internal process and system API layers sit behind this private endpoint with no public exposure at all, while the externally-published experience API is exposed through Azure Front Door with a WAF policy in front of it — two different trust boundaries, each getting the control appropriate to it.
Common use cases
Section titled “Common use cases”| Use case | Control | Notes |
|---|---|---|
| Service-to-service API calls, no end user involved | OAuth2 client credentials | Standard machine-to-machine auth flow |
| High-trust partner or regulated data link | mTLS (in addition to OAuth2) | Verifies both endpoints, not just the caller’s token |
| Shared API with multiple internal or external consumers | Rate limiting per consumer | Prevents one consumer from degrading service for others |
| API or event schema needs to change | Contract governance + versioning | Gives existing consumers a deprecation window instead of a surprise break |
Advanced details
Section titled “Advanced details”- Token scope: grant OAuth2 client credentials tokens the minimum scope needed for the specific integration, not a broad “full access” token reused everywhere.
- mTLS overhead: mutual TLS adds certificate management overhead — reserve it for connections where verifying both endpoints is worth that cost, rather than applying it universally by default.
- Governance without bureaucracy: contract governance can be as lightweight as a required schema-diff check in CI that flags breaking changes — it doesn’t require a heavyweight review board for every change.
Quick reference
Section titled “Quick reference”| Term | Meaning |
|---|---|
| OAuth2 client credentials | An OAuth2 flow where a system authenticates as itself, not on behalf of a user |
| mTLS | Mutual TLS — both client and server present certificates to verify each other |
| Rate limiting / throttling | Capping how often a consumer can call an API in a given period |
| Contract governance | The process ensuring API/event contract changes don’t silently break consumers |
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
| A shared API keeps degrading during traffic spikes from one consumer | No per-consumer rate limiting | Add rate limits scoped per consumer, not just a global limit |
| A partner integration silently breaks after a schema change | No contract governance / versioning | Add a schema-diff check in CI and a deprecation window policy |
| Static API keys shared across multiple services | No machine identity per caller | Move to OAuth2 client credentials so each caller has its own revocable identity |
Check your understanding
Section titled “Check your understanding”- Why is mTLS described as verifying “both sides,” compared to a typical browser HTTPS connection?
- What would you check in the worked example to confirm the rate limit is actually per-consumer and not global?
Related pages
Section titled “Related pages”Part of Introduction to Integration Architecture. Builds on API-Led Connectivity; see also Integration Platforms & Middleware for where gateways fit, and the Glossary for term definitions.