Skip to content

Add token binding to MicrosoftIdentityMessageHandler#3743

Open
cpp11nullptr wants to merge 2 commits intomasterfrom
iepoly/extend-microsoft-identity-message-handler-with-token-binding
Open

Add token binding to MicrosoftIdentityMessageHandler#3743
cpp11nullptr wants to merge 2 commits intomasterfrom
iepoly/extend-microsoft-identity-message-handler-with-token-binding

Conversation

@cpp11nullptr
Copy link
Contributor

No description provided.

@cpp11nullptr cpp11nullptr requested a review from a team as a code owner March 4, 2026 17:20
}
catch (MicrosoftIdentityAuthenticationException)
{
throw;
Copy link
Member

Choose a reason for hiding this comment

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

Was this forgotten?

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1


/// <summary>
/// Sends an HTTP request with authentication header injection.
/// When token binding (mTLS PoP) is configured via <see cref="AuthorizationHeaderProviderOptions.ProtocolScheme"/>,
Copy link
Member

Choose a reason for hiding this comment

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

nit: use a remarks section for this, it's quite advanced scenario.

}

/// <summary>
/// Initializes a new instance of the <see cref="MicrosoftIdentityMessageHandler"/> class with mTLS PoP token binding support.
Copy link
Member

Choose a reason for hiding this comment

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

nit: in public docs, let's mention the RFC 8705

],
"SendX5c": true
},
"SecureApi": {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use the same formalism as the rest of the docs:

"DownstreamApis":
{
 "SecureApi":{ }
}

Copy link
Collaborator

@jmprieur jmprieur left a comment

Choose a reason for hiding this comment

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

There are a couple of things to improve:

  • the RequiredService seems inconsistent with the option. Either use GetService or explain why required is fine. I think it's a breaking change, personally. you don't want to break Aspire!!
  • Fragile code that can be improved
  • +some questions/remarks

client.BaseAddress = new Uri("https://secure-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
configuration.GetSection("SecureApi"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

would become DownstreamApis:SecureApi

**appsettings.json:**
```json
{
"SecureApi": {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same thing: please have a DownstreamApis section in which the secure Api is to maintain consistency with the rest of the samples in the library.

{
var headerProvider = sp.GetRequiredService<IAuthorizationHeaderProvider>();
return new MicrosoftIdentityMessageHandler(headerProvider);
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't that a breaking change? Is the IHttpClientFactory always provided?
Shouln'd you use GetService and test if it's null? Given the other constructor if MicrosoftIdentityMessageHandler accepts null, it's strange to have a required service that could throw?

{
var headerProvider = sp.GetRequiredService<IAuthorizationHeaderProvider>();
return new MicrosoftIdentityMessageHandler(headerProvider, options);
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same question. Please explain why this is ok as writen.


var headerProvider = sp.GetRequiredService<IAuthorizationHeaderProvider>();
return new MicrosoftIdentityMessageHandler(headerProvider, options);
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

idem


var headerProvider = sp.GetRequiredService<IAuthorizationHeaderProvider>();
return new MicrosoftIdentityMessageHandler(headerProvider, options);
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

idem

/// If <see langword="null"/>, each request must specify its own authentication options or an exception will be thrown.
/// </param>
/// <param name="mtlsHttpClientFactory">
/// Optional factory for creating HTTP clients configured with mTLS client certificates for token binding
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional ... so why do the Add use a Required service?
There is an inconsistency to resolve here?

/// </exception>
/// <example>
/// <para>Usage with mTLS PoP token binding:</para>
/// <code>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please remove this sample which has no place here. You don't want customers to instanciate MicrosoftIdentityMessageHandler directly but use the extension methods.

}
catch (MicrosoftIdentityAuthenticationException)
{
throw;
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1

private static DownstreamApiOptions CreateDownstreamApiOptionsFromMessageHandlerOptions(
MicrosoftIdentityMessageHandlerOptions options, IList<string> scopes)
{
return new DownstreamApiOptions
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is fragile.
Please add a copy constructor in MicrosoftIdentityMessageHandlerOptions leveraging the AuthorizationHeaderProviderOptions copy constructor and copying the scopes (maybe with cloning the collection)?

@bgavrilMS
Copy link
Member

@tlupes - this is related to pure mTLS option, a review from you would be good.

string authHeader;

// Check if mTLS PoP token binding is requested
if (string.Equals(options.ProtocolScheme, TokenBindingProtocolScheme, StringComparison.OrdinalIgnoreCase)
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic looks nearly identical to the logic for DownstreamApi; can we centralize this logic, or is the plan to use this message handler internally to DownstreamApi?

@tlupes
Copy link
Contributor

tlupes commented Mar 5, 2026

@tlupes - this is related to pure mTLS option, a review from you would be good.

It looks very similar to how DownstreamApi works, which means it should be easy to transfer over. Centralizing the logic would make things easier.

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.

4 participants