Skip to content

[Bug] WithClientName doesn't send the x-app-header unless WithLogging is called. #4979

@craigb

Description

@craigb

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:

_headers.Add(OAuth2Header.AppName, requestContext.Logger.ClientName);
. Simply calling .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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions