Chapter 4 of 6 · Decisions and boundaries

Delegated API access with OAuth on-behalf-of

Optional module · Draft 4.5 hours

Chapter 4 of 6

Decisions and stop conditions#

Choose OBO for the right reason#

Use OBO only when the downstream API must evaluate the signed-in user. Typical signals include user-owned records, per-user entitlements, or a downstream policy that names the user.

Use application-only authorization when the workload reads shared data, runs in the background, or needs the same authority for every caller. Record signed-in user OBO in control-definition.json for this module. Do not configure an application-only managed identity in its place.

Keep token audiences separate#

The inbound token audience is the middle tier. The exchanged token audience is the downstream API. They must differ.

The claim examples and Conditional Access claims-challenge boundary contain no token values.

Stop if any design forwards the inbound bearer token to the downstream API. Also stop when:

  • the client requests a token directly for the downstream API and sends it through the middle tier;
  • the middle tier accepts tokens issued for another audience;
  • the downstream scope is broader than the implemented read operation;
  • an application-only token can enter the OBO path;
  • the middle-tier API uses a custom signing key that the downstream trust chain cannot validate;
  • the middle tier falls back to an application permission after delegated exchange fails; or
  • the downstream API trusts exchange success without checking user access to the resource.

The identity owner approves the client-to-middle-tier and middle-tier-to-downstream delegated permissions. Record the exact scope IDs and consent type in identity/app-registrations.json.

Stop when the consent owner is unnamed, a requested scope is unresolved, or an existing tenant-wide grant would be broadened without an explicit decision. The configure scripts preserve unrelated permissions. They must not replace a complete permission collection with the module's entries. Obtain downstream delegated consent before runtime; the middle tier has no interactive surface where it can ask the user.

Protect the confidential client#

The middle tier authenticates with the certificate described in identity/key-vault-certificate-binding.json. MSAL reads the protected PFX path. Only the middle-tier workload may read the private key.

Stop if the certificate is committed, passed as a command argument, printed, copied into a build artifact, or mounted where another workload can read it. Stop if the registered thumbprint differs from the certificate exposed to the middle tier. This path requires an exportable Key Vault certificate. An HSM-backed, nonexportable key cannot be mounted as a PFX and needs a different client-authentication design.

Validate before exchange#

The middle tier validates the issuer, middle-tier audience, tenant, calling client, delegated scope, token lifetime, and signed-in user claims before using the token as a user assertion. The authoritative configuration file is governance/token-claim-contract.json.

An OBO exchange does not remove Conditional Access. Return a supported claims challenge or authorization failure to the approved client flow. Never turn it into an anonymous retry or an application-only call.

Keep telemetry payload-free#

Use the allowlist in the token-claim contract. Do not log the inbound authorization header, user assertion, exchanged token, request body, downstream body, or certificate material. The threat model in governance/threat-model.md treats any such capture as a stop condition.

Optional module

Delegated API access with OAuth on-behalf-of slide deck