-
Notifications
You must be signed in to change notification settings - Fork 381
Description
Library version used
4.65.0
.NET version
NET8.0, but can repro in NET6, NET472, and NET48
Scenario
ConfidentialClient - service to service (AcquireTokenForClient)
Is this a new or an existing app?
This is a new app or experiment
Issue description and reproduction steps
Onboarding to use MSI from within my RP. A recommendation from MIRP team is to use .WithClientName("MSI.<RP namespace>"). Using a custom HttpClientFactory, I can see that the request doesn't contain x-app-name header as documented. I can send my own headers in the token request as a workaround, so it's not a huge deal.
However, looking into it further, it appears that the header is dependent on the logger:
Line 228 in ac1cb05
| _headers.Add(OAuth2Header.AppName, requestContext.Logger.ClientName); |
.WithLogging(NullIdentityModelLogger.Instance) fixes the issue, and the request to the authority has the header properly populated.
This seems like a bug. It's certainly unexpected behavior.
Relevant code snippets
var app = ConfidentialClientApplicationBuilder
.Create(metadata.ClientId.ToString())
.WithTenantId(metadata.TenantId.ToString())
.WithCertificate(certificate, sendX5C: true)
.WithAuthority(authority, validateAuthority: false)
.WithInstanceDiscoveryMetadata(regionalDiscoveryMetaData)
// There appears to be a bug in MSAL.NET where the ClientName is not being sent to the server
// This seems to happen when WithLogging is not called.
.WithClientName(ClientName)
.WithLogging(NullIdentityModelLogger.Instance) // <-- the fix to send client name
.WithHttpClientFactory(MockHttpClientFactory.WithVerification(AssertMethod));
var token = await credential.GetTokenAsync(new TokenRequestContext([$"https://{Guid.NewGuid()}.local/.default"]), CancellationToken.None);
void AssertMethod(HttpRequestMessage request, HttpResponseMessage response)
{
request.Headers.Should().ContainKey("x-app-name").WhoseValue.Should().Contain("MSI.Microsoft.Experimentation");
}Expected behavior
Setting .WithClientName() on the builder should ensure that the client name is sent, regardless of any other calls.
Identity provider
Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)
Regression
No response
Solution and workarounds
Later in each actual request using the AcquireTokenForClientParameterBuilder call .WithExtraHttpHeaders and set x-app-name to the value.