DevEx - Add documentation for bearer-over-mTLS user flows - #3997
Gladwin Johnson VR (gladjohn) wants to merge 3 commits into
Conversation
Document the use of bearer-over-mTLS client authentication for user flows, including configuration examples and flow coverage.
| | Set on | the **credential** (`ClientCredentials`) | the **downstream API** options | | ||
| | mTLS applies to | app → ESTS **client auth** | the **downstream API** call | | ||
| | Access token | **bearer** | **sender-constrained** (PoP) | | ||
| | Credential | certificate only | certificate, MI, FIC-with-MI | |
There was a problem hiding this comment.
Not cert-only. ConfidentialClientApplicationBuilderExtension honors the flag for CredentialType.SignedAssertion too (→ WithBoundClientAssertion, throws MissingTokenBindingCertificate if the provider can't bind). Only Secret ignores it. As written this turns away the FIC audience.
| | Credential | certificate only | certificate, MI, FIC-with-MI | | |
| | Credential | certificate, or signed assertion (FIC / MI / OIDC IdP) | certificate, MI, FIC-with-MI | |
Line 138 needs the same correction.
| present the cert at TLS (x5c auto-enabled). | ||
| 3. MSAL returns a **bearer** token; IdWeb's default `MsalMtlsHttpClientFactory` | ||
| supplies the mTLS transport — no extra wiring. | ||
| 4. `IDownstreamApi` calls downstream with `Authorization: Bearer` as usual. |
There was a problem hiding this comment.
Missing the highest-value devex piece: how a dev confirms it's actually on. One line does it —
| 4. `IDownstreamApi` calls downstream with `Authorization: Bearer` as usual. | |
| 4. `IDownstreamApi` calls downstream with `Authorization: Bearer` as usual. | |
| ## Verifying it works | |
| `AuthenticationResultMetadata.TokenEndpoint` contains `mtlsauth.` when the | |
| credential is bound, and `login.microsoftonline.com` when it isn't. That is the | |
| assertion the tests in #3996 make. |
There was a problem hiding this comment.
Thanks. But, I don’t think we should add this here. Endpoint selection and AuthenticationResultMetadata.TokenEndpoint are handled by MSAL internally and are not part of the IdWeb developer contract. This document should focus on the IdWeb configuration and the bearer token returned to the downstream API.
| ``` | ||
|
|
||
| Only delta vs. a plain-bearer config: the `"UseBoundCredential": true` line, and | ||
| a **certificate** source (not `ClientSecret` — bearer-over-mTLS is cert-only). |
There was a problem hiding this comment.
Worth stating that this fails silently: case CredentialType.Secret just calls WithClientSecret and drops the flag — no log, no throw. Dev sets UseBoundCredential: true on a secret, sees no error, assumes mTLS. Should we log a warning in idweb?
There was a problem hiding this comment.
Thanks. I agree the user-visible behavior should be clear, but the internal credential dispatch and logging behavior are outside this document’s scope. I’ll state that UseBoundCredential has no effect on client-secret credentials. Any warning or fail-fast behavior should be tracked as a separate implementation change.
| 1. `UseBoundCredential: true` → IdWeb builds the CCA with | ||
| `WithCertificate(cert, new CertificateOptions { SendCertificateOverMtls = true })` | ||
| (`ConfidentialClientApplicationBuilderExtension.WithClientCredentialsAsync`). |
There was a problem hiding this comment.
Worth a sentence here: GetApplicationKey appends +bound per credential, so a bound config never reuses the unbound CCA/cache entry. That's the first question anyone flipping this flag on an existing deployment will ask.
There was a problem hiding this comment.
Thanks. CCA cache-key construction and the +bound discriminator are internal IdWeb implementation details, not a supported developer contract. We should validate bound/unbound isolation in tests, but I don’t think the internal cache-key format belongs in this developer-experience document.
| | App token (daemon) | `RequestAppToken` / `CallApiForApp` | ✅ shipped | | ||
| | Web-app sign-in | `AddMicrosoftIdentityWebApp` | ✅ via #6009 | | ||
| | On-behalf-of | `EnableTokenAcquisitionToCallDownstreamApi` | ✅ via #6009 | | ||
| | Silent / refresh-token | `AcquireTokenSilent` | ✅ via #6009 | |
There was a problem hiding this comment.
Entry-point column is MSAL-level here — AcquireTokenSilent isn't something the IdWeb dev calls. The IdWeb-level equivalents are IAuthorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync and IDownstreamApi.CallApiForUserAsync.
Rows 36-37 have the inverse problem: they name registration methods, not call sites. Worth making the column consistently one layer.
| | Silent / refresh-token | `AcquireTokenSilent` | ✅ via #6009 | | |
| | Silent / refresh-token | `IAuthorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync` | ✅ via #6009 | |
There was a problem hiding this comment.
Fixed in 1e914a5. The column is now IdWeb usage, the app and OBO rows use IDownstreamApi / IAuthorizationHeaderProvider, and silent refresh is described as behavior handled internally rather than as a developer call to AcquireTokenSilent.
| * Bump `Microsoft.Identity.Client` to the build containing #6009. | ||
| * Delegated-flow tests (auth-code, OBO, silent). | ||
| * Two samples: `web-app-bound-credential`, `web-api-obo-bound-credential`. |
There was a problem hiding this comment.
Stale: the MSAL bump is done (4.87.0 already referenced) and delegated-flow tests landed in #3996 — worth linking so readers see current state.
There was a problem hiding this comment.
Fixed in 1e914a5. The section now records MSAL 4.87.0 and the authorization-code, OBO, and direct refresh-token tests from #3996 as complete. Actual silent-acquisition refresh coverage, samples, and public documentation remain outstanding.
|
Thanks for the review folks - forgot I had this open. I will address these comments and respond back |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c958606f-3471-4310-8715-83d1081964f5
Document the use of bearer-over-mTLS client authentication for user flows, including configuration examples and flow coverage.