Credential system refactor: unified context, canonical matrix, eliminate dead code#5831
Closed
Copilot wants to merge 3 commits into
Closed
Credential system refactor: unified context, canonical matrix, eliminate dead code#5831Copilot wants to merge 3 commits into
Copilot wants to merge 3 commits into
Conversation
…edentialMaterial, and CredentialMaterialResolver Co-authored-by: gladjohn <90415114+gladjohn@users.noreply.github.com>
…nes and convert synchronous tests to non-async Co-authored-by: gladjohn <90415114+gladjohn@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Refactor credential system to improve architecture
Credential system refactor: unified context, canonical matrix, eliminate dead code
Mar 10, 2026
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.
Rewrites MSAL.NET's internal credential resolution architecture to replace the
AddConfidentialClientParametersAsync/ClientCredentialApplicationResultpattern with a clean, decoupled pipeline.Core design changes
IClientCredentialinterface — replacesAddConfidentialClientParametersAsync(OAuth2Client, AuthenticationRequestParameters, ...)withGetCredentialMaterialAsync(CredentialContext, CancellationToken). Credentials now return data; they no longer write directly toOAuth2Client.CredentialContext(immutable struct) — single input carrying all 12 resolution parameters (ClientId,TokenEndpoint,Mode,Claims,CryptographyManager,SendX5C,UseSha2,AzureRegion, …). Replaces scattered parameter passing.CredentialMaterial(output class) — replacesClientCredentialApplicationResult. Fields:TokenRequestParameters(never null),Source(Static/Callback),ResolvedCertificate(optional).ClientAuthModeenum (Regular/MtlsMode) — replaces theIsMtlsPopRequested+UseJwtPopClientAssertionboolean pair.CredentialMaterialResolver— central static coordinator invoked exactly once per request byTokenClient. BuildsCredentialContext, calls the credential, validates invariants (InvalidOperationExceptionfor null returns;MsalClientExceptionfor unsupported mode combinations).CREDENTIAL_MATRIX.cs— documentation-only file enumerating all 10 supported (credential-type × mode) combinations and theirTokenRequestParameters/ResolvedCertificateoutputs.Credential implementations rewritten (
CertificateAndClaimsClientCredential,SecretStringClientCredential,SignedAssertionClientCredential,ClientAssertionDelegateCredential,ClientAssertionStringDelegateCredential) — each now returnsCredentialMaterial; unsupported mTLS combinations throwMsalClientException(InvalidCredentialMaterial).Dead code removed —
ClientCredentialApplicationResultgutted; Stopwatch tracking, hash-prefix helpers, and defensive parameter guards deleted from credential implementations.MsalError.InvalidCredentialMaterialadded (public constant, all platformPublicAPI.Unshipped.txtfiles updated).Testing
18 new unit tests in
CredentialMatrixTests.cscover every matrix row (X509Cert × Regular/Mtls, Secret × Regular/Mtls, static JWT × Regular/Mtls, JWT+cert callback × Regular/Mtls) plus edge cases: null certificate from callback, empty assertion, nullTokenRequestParametersat construction. All 18 pass; existing failures are pre-existing (missing test resource files, Windows-only CNG on Linux CI).Performance impact
No measurable impact. One fewer async call per token request (resolver path eliminates the double-call to assertion providers that existed in
MtlsPopParametersInitializer).Documentation
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
contoso.adfs.contoso.com/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 44807 --endpoint 127.0.0.1:044807 --role client --parentprocessid 7180 --telemetryoptedin false "$k=".$v["local--norc(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 42683 --endpoint 127.0.0.1:042683 --role client --parentprocessid 7424 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 33073 --endpoint 127.0.0.1:033073 --role client --parentprocessid 9036 --telemetryoptedin false(dns block)contoso.b2clogin.com/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 44807 --endpoint 127.0.0.1:044807 --role client --parentprocessid 7180 --telemetryoptedin false "$k=".$v["local--norc(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 42683 --endpoint 127.0.0.1:042683 --role client --parentprocessid 7424 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 33073 --endpoint 127.0.0.1:033073 --role client --parentprocessid 9036 --telemetryoptedin false(dns block)login.microsoftonline.com/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 44807 --endpoint 127.0.0.1:044807 --role client --parentprocessid 7180 --telemetryoptedin false "$k=".$v["local--norc(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 42683 --endpoint 127.0.0.1:042683 --role client --parentprocessid 7424 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 37453 --endpoint 127.0.0.1:037453 --role client --parentprocessid 7669 --telemetryoptedin false(dns block)some.url.dsts.core.azure-test.net/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 44807 --endpoint 127.0.0.1:044807 --role client --parentprocessid 7180 --telemetryoptedin false "$k=".$v["local--norc(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 42683 --endpoint 127.0.0.1:042683 --role client --parentprocessid 7424 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/Microsoft.Identity.Test.Unit.deps.json /home/REDACTED/work/microsoft-authentication-library-for-dotnet/microsoft-authentication-library-for-dotnet/tests/Microsoft.Identity.Test.Unit/bin/Debug/net8.0/testhost.dll --port 33073 --endpoint 127.0.0.1:033073 --role client --parentprocessid 9036 --telemetryoptedin false(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
Credential System Refactor - Complete Rewrite
Overview
This PR comprehensively rewrites the credential system to address all 32 code review comments from PR #5748. The refactor introduces a clean, testable architecture for credential resolution.
Key Changes
1. Single
ClientAuthModeEnum (Addresses comments #2795377908, #2799230854)IsMtlsPopRequested,UseJwtPopClientAssertion)Regular(JWT/secret) andMtlsMode(certificate-only)2. Unified
CredentialContext(Addresses comments #2795282172, #2795298829, #2798482280)CredentialRequestContextandMtlsValidationContextClientId,TokenEndpoint,Mode,Claims,ClientCapabilities,CryptographyManager,SendX5C,UseSha2,ExtraClientAssertionClaims,ClientAssertionFmiPath,AuthorityType,AzureRegion3.
CredentialMaterialOutput (Addresses comments #2798443132, #2798439218, #2798551197)ClientCredentialApplicationResultTokenRequestParameters(never null),Source(Static/Callback),ResolvedCertificate(optional)4.
CredentialMaterialResolver(Addresses comments #2798553940, #2798559671, #2798550191)InvalidOperationExceptionMsalClientException5. Canonical Credential Matrix (Addresses comment #2798409064)
CREDENTIAL_MATRIX.csMsalClientException6. Removed Dead Code (Addresses comments #2795673346, #2795667204, #2798451217, #2798444768, #2798448380, #2798413416)
ClientCredentialApplicationResultclassCredentialMaterialMetadata7. Proper Enum Usage (Addresses comment #2795347697)
CredentialSourceenum (Static vs Callback) instead of string8. Exception Taxonomy (Addresses comments #2798550191, #2798551197, #2798417759)
InvalidOperationExceptionfor invariant violations (credential returned null, TokenRequestParameters is null)MsalClientExceptionfor configuration errors (unsupported mode combinations)9. Explicit CancellationToken (Addresses comment #2798464735)
CancellationTokenfromCredentialContextGetCredentialMaterialAsync10. Comprehensive Test Coverage (16 tests)
Interface Changes
IClientCredential (Before)
IClientCredential (After)
Benefits
✅ Cleaner Architecture - Credentials focus on "what to produce", not "how to apply"
✅ Type Safety - Enums instead of strings/booleans
✅ Single Source of Truth - Canonical matrix documents all supported combinations
✅ Better Testability - No OAuth2Client coupling, immutable context
✅ Explicit Error Handling - Clear distinction between invariant violations and config errors
✅ Reduced Complexity - No dead code, no defensive guards in product code
✅ Standards Compliance - Follows .NET conventions
Files Modified
ClientAuthMode.cs(NEW)CredentialContext.cs(NEW)CredentialMaterial.cs(NEW)CredentialMaterialResolver.cs(NEW)CREDENTIAL_MATRIX.cs(NEW)IClientCredential.cs(MODIFIED - new method signature)CertificateAndClaimsClientCredential.cs(REWRITTEN)SecretStringClientCredential.cs(REWRITTEN)SignedAssertionClientCredential.cs(REWRITTEN)ClientAssertionDelegateCredential.cs(REWRITTEN)ClientAssertionStringDelegateCredential.cs(REWRITTEN)ClientCredentialApplicationResult.cs(DELETED)This pull request was created from Copilot chat.
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.