Skip to content

DevEx - Add documentation for bearer-over-mTLS user flows - #3997

Open
Gladwin Johnson VR (gladjohn) wants to merge 3 commits into
masterfrom
gladjohn-patch-3
Open

Gladwin Johnson VR (gladjohn) wants to merge 3 commits into
masterfrom
gladjohn-patch-3

Conversation

@gladjohn

Copy link
Copy Markdown
Contributor

Document the use of bearer-over-mTLS client authentication for user flows, including configuration examples and flow coverage.

Document the use of bearer-over-mTLS client authentication for user flows, including configuration examples and flow coverage.
@gladjohn
Gladwin Johnson VR (gladjohn) requested a review from a team as a code owner August 6, 2026 15:45
Comment thread docs/design/User-flow-bound-credential-mtls-devex.md Outdated
| 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 |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
| 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the highest-value devex piece: how a dev confirms it's actually on. One line does it —

Suggested change
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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +118 to +120
1. `UseBoundCredential: true` → IdWeb builds the CCA with
`WithCertificate(cert, new CertificateOptions { SendCertificateOverMtls = true })`
(`ConfidentialClientApplicationBuilderExtension.WithClientCredentialsAsync`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 |

@Robbie-Microsoft Robbie-Microsoft Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
| Silent / refresh-token | `AcquireTokenSilent` | ✅ via #6009 |
| Silent / refresh-token | `IAuthorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync` | ✅ via #6009 |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +129 to +131
* 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`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Robbie-Microsoft Robbie-Microsoft left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

above comments

@gladjohn

Copy link
Copy Markdown
Contributor Author

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants