Repository navigation
Support custom certificate-aware mTLS HTTP pipelines - #974
Draft
Robbie-Microsoft wants to merge 19 commits into
Draft
Robbie-Microsoft wants to merge 19 commits into
Robbie-Microsoft wants to merge 19 commits into
Conversation
Allow custom HTTP pipelines to create isolated certificate-bearing token clients using MtlsBindingContext. Preserve networking policy, pooling and Requests TLS compatibility, enforce observable transport contracts, and document ownership and trust boundaries. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve custom certificate-scoped pipelines, integrate parent transport and cache fixes, and reconcile redirect test contracts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The endpoint guard raises an exception for otherwise compatible custom responses whose URL metadata is a URL object.
1 open issue
What changed in this PR
Adds certificate-aware custom HTTP pipelines to the existing mTLS token flow while preserving the default transport and ordinary HTTP behavior.
Changes:
- Adds an opt-in client factory and a public Requests adapter helper.
- Enforces pipeline isolation, request restrictions, and endpoint checks.
- Documents ownership requirements and adds a runnable sample with unit and local TLS coverage.
| File | Description |
|---|---|
tests/test_mtls_http_client.py |
Tests custom factories, isolation, lifecycle, and local TLS behavior. |
tests/test_application.py |
Updates redirect tests and transport cleanup. |
sample/confidential_client_mtls_pop_sample.py |
Updates comments to reference the custom pipeline sample. |
sample/confidential_client_mtls_http_client_sample.py |
Demonstrates policy-preserving pipelines and explicit cleanup. |
msal/mtls.py |
Adds adapter customization, ownership tracking, and endpoint guards. |
msal/application.py |
Integrates lazy custom pipeline creation and request validation. |
docs/index.rst |
Documents factory usage, trust boundaries, and lifecycle responsibilities. |
Review effort: Balanced
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Custom certificate-bearing authentication pipelines introduce security-sensitive isolation, redirect, and lifecycle contracts that warrant final human review.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
Distinguish the inherited live matrix from custom HTTP factory loopback TLS coverage without claiming cross-SDK live factory parity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Allow the mocked legacy release-skip attribute to be created when the E2E module was imported without TRAVIS_TAG. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Redistribute the approved factory recorder/privacy/lifecycle slice from combined source 0cd290d without importing enabled Bearer-over-mTLS or real FIC integration. Preserve sample middleware, factory ownership, safe diagnostics, and the explicit loopback TLS floor. Shared generic E2E fixtures are supplied by the dependent foundation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the extensibility branch inventory separate from combined Bearer/FIC scenarios and reuse the foundation certificate fixture for rendered traceback redaction. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> # Conflicts: # tests/test_e2e.py
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Assert the owned shared transport closes once without closing endpoint wrappers, while retaining the legacy-layout assertions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> # Conflicts: # tests/test_mtls_e2e_helpers.py
Robbie-Microsoft
added a commit
that referenced
this pull request
Oct 27, 2026
Inherit the factory recorder and privacy guards in their owner modules, keep combined-only Bearer/FIC transport cases and the full 21-method live inventory, and avoid duplicate core collection. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Robbie-Microsoft
added a commit
that referenced
this pull request
Oct 27, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Catch Requests errors at the hidden outer POST boundary so real downstream DNS frames cannot render posted assertions or refresh tokens. Cover ordinary and derived clients through the actual Requests/urllib3 path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rethrow only the private recorder transport failure outside OAuth call frames. Exercise real application client-credential and OBO DNS failures with expanded pytest tracebacks. Keep cert=None cold/cache behavior covered without changing production code. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Python 3.9 renders the inline dummy assertion in the visible leaf source even after transport exceptions are sanitized. Keep only the acquisition call in a hidden helper; leave every validation assertion visible and preserve all full/prefix/suffix privacy checks. Reproduced before and verified after on Python 3.9.25 with pytest 8.4.2. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Robbie-Microsoft
added a commit
that referenced
this pull request
Oct 27, 2026
Preserve the equivalent hidden combined invalid-grant acquisition boundary and all strict existing validation; no combined tree change is required. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the shared private validation sentinel only around token_request_summary and rethrow it outside OAuth frames with a static validation diagnostic, distinct from transport errors. Cover real-app bad JSON and signed-assertion validation in client credentials and OBO without masking unrelated assertions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Robbie-Microsoft
added a commit
that referenced
this pull request
Oct 27, 2026
…rom #974 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
3 tasks
Nilesh Choudhary (4gust)
approved these changes
Oct 29, 2026
Gladwin Johnson VR (gladjohn)
requested changes
Oct 29, 2026
Gladwin Johnson VR (gladjohn)
left a comment
Contributor
There was a problem hiding this comment.
I do not see a support for non-exportable CNGs. This is the key scenario.
Robbie-Microsoft
marked this pull request as draft
October 29, 2026 20:04
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Scope
Follow-up to #938. Adds opt-in custom HTTP-pipeline support for the mTLS token endpoint. The default certificate-bearing transport and ordinary non-mTLS custom HTTP behavior remain unchanged.
Developer experience
A custom
http_clientopts in by addingcreate_mtls_client(binding_context)alongside its existing ordinaryget/postmethods. The argument is the publicmsal.MtlsBindingContext, not a token result. There is no marker class or new application constructor parameter.MtlsBindingContext.create_requests_adapter(**HTTPAdapter_options)reuses MSAL's certificate-bearing Requests transport, CA selection, proxy handling, and Requests-version compatibility. Other HTTP implementations can usecreate_ssl_context(verify=...)after resolving their effective verification policy.sample/confidential_client_mtls_http_client_sample.pyis a runnable example retaining middleware, CA/proxy/environment settings, timeout, retry, and pooling policy. It owns and closes both ordinary and derived pipelines.Isolation and ownership
post(url, **kwargs), isolated connection pools and TLS sessions, and the required networking/middleware policy. The factory owns cleanup, including partial constructions; MSAL does not close caller-owned clients.binding_certificateis returned only for a finalmtls_popresult, never for ordinary Bearer. Downgraded responses remain rejected and uncached.Validation
Unit and integration coverage includes factory validation, default/ordinary compatibility, concurrent construction, client reuse, lifecycle ownership, redirects, request overrides, and token/HTTP cache isolation.
Loopback TLS tests verify the selected peer certificate, ordinary/discovery traffic without a client certificate, middleware and timeout policy, CA/proxy settings, isolated connection pools, certificate rotation, and failure without fallback.