Skip to content

Refactor to include mtls with managed cert#5692

Closed
neha-bhargava wants to merge 4 commits intomainfrom
nebharg/managedCertMtlsRefactor
Closed

Refactor to include mtls with managed cert#5692
neha-bhargava wants to merge 4 commits intomainfrom
nebharg/managedCertMtlsRefactor

Conversation

@neha-bhargava
Copy link
Contributor

@neha-bhargava neha-bhargava commented Jan 30, 2026

Fixes #5608

Changes proposed in this request
Centralize and simplify certificate resolution for MTLS Proof-of-Possession while maintaining backward compatibility and existing validation behavior.

Refactor the mtls flow and include mtls with cert provider as well

Testing

Performance impact

Documentation

  • All relevant documentation is updated.

@neha-bhargava neha-bhargava requested a review from a team as a code owner January 30, 2026 23:33
@neha-bhargava neha-bhargava marked this pull request as draft January 30, 2026 23:33
/// <summary>
/// Shared validation utilities for client certificate scenarios.
/// </summary>
internal static class ClientCertificateValidation
Copy link
Member

Choose a reason for hiding this comment

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

It seems a bit overkill to have a full class for a helper (static) method. Consider adding to ClientCertificateOrchestrator

/// </exception>
public static async Task<ClientCertificateContext> ResolveCertificateAsync(
IClientCredential credential,
IServiceBundle serviceBundle,
Copy link
Member

Choose a reason for hiding this comment

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

IServiceBundle is a "god" object. Ideally we should not pass it around. Maybe the Config is enough?

/// Indicates whether MTLS Proof-of-Possession is requested for this authentication operation.
/// When true, the certificate (if provided) will be used for TLS binding rather than just JWT signing.
/// </summary>
public bool IsMtlsPopRequested { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

I don't think consumers of AssertionRequestOptions (e.g. OneCert) need to know this?

/// <summary>
/// Describes how a client certificate is used in the authentication flow.
/// </summary>
internal enum ClientCertificateUsage
Copy link
Member

@bgavrilMS bgavrilMS Feb 2, 2026

Choose a reason for hiding this comment

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

I wonder if we can simplify a bit more here, to decouple the Credential from the usage?

Credentials in OAuth are of 2 types: JWT (FIC, client_assertion) and X509Certificate2 (for mTLS). MSAL decides if to request the token over mTLS (in which case it MUST have access to X509Certificate2 obj) or over regular HTTPS.

There are 4 credentials:

  • secrets (extra POST param)
  • certificates (extra POST param or mTLS)
  • FIC - regular and bound ... in case of regular FIC, this is extra POST param only. But in case of bound FICs, the credential is a combination of a { jwt, x509certificate}. So ... bearer FIC - extra POST param. Bound FIC - mTLS with custom POST params

So maybe the IClientCredential interface is really

internal interface IClientCredential 
{
     Task<CredentialMaterial> GetCredentialMaterialAsync(bool mTLSRequired)
}

internal class  CredentialMaterial
 {
     public X509Certificate2 MtlsCertificate { get; }
     public IDictionary<string, string> TokenRequestParameters { get; }
}

Copy link
Member

Choose a reason for hiding this comment

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

We can also have a dedicated WithBoundClientAssertion(lambda) @gladjohn if it makes the API cleaner.

Copy link
Contributor

Choose a reason for hiding this comment

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

agreed,

  1. Single Responsibility: Concrete credential classes only know "what credentials I can provide" not "how or when they're used"

  2. Inspection Without Implementation Knowledge: The caller inspects CredentialMaterial (via the getter) to decide if it has mTLS cert or what parameters to use, but the credential class itself has zero knowledge of mTLS context or usage intent.

Comment on lines +61 to +62
certContext = await ClientCertificateOrchestrator.ResolveCertificateAsync(
ServiceBundle.Config.ClientCredential,
Copy link
Contributor Author

@neha-bhargava neha-bhargava Feb 3, 2026

Choose a reason for hiding this comment

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

This is where the orchestrator is called CC: @gladjohn

@neha-bhargava
Copy link
Contributor Author

Closing as the work was duplicated with some tech debt in PR #5670

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.

[Feature Request] Update the logic to handle mtls flow

3 participants

Comments