Skip to content

Regression in Microsoft.Windows.Client 4.61.1? - System.TypeLoadException #4789

@DerAlbertCom

Description

@DerAlbertCom

Library version used

4.61.1

.NET version

.NET 8

Scenario

ConfidentialClient - service to service (AcquireTokenForClient)

Is this a new or an existing app?

The app is in production, and I have upgraded to a new version of MSAL

Issue description and reproduction steps

We had an auto-upgrade of Microsoft.Identity.Client from 4.61.0 to 4.61.1 with renovate. Suddenly, our API Token Acquisition did not work anymore. We get the Exception.

System.TypeLoadException: Could not load type 'Microsoft.Identity.Client.Extensibility.AcquireTokenForClientBuilderExtensions' from assembly 'Microsoft.Identity.Client, Version=4.61.1.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae'.

at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForAppAsync(String scope, String authenticationScheme, String tenant, TokenAcquisitionOptions tokenAcquisitionOptions)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForAppAsync(String scope, String authenticationScheme, String tenant, TokenAcquisitionOptions tokenAcquisitionOptions)
at Microsoft.Identity.Web.TokenAcquisition.GetAccessTokenForAppAsync(String scope, String authenticationScheme, String tenant, TokenAcquisitionOptions tokenAcquisitionOptions)
at Carmen.Position.Infrastructure.ExternalServices.DownstreamApiTokenAcquisitionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /home/vsts/work/1/s/backend/src/Infrastructure/ExternalServices/DownstreamApiTokenAcquisitionHandler.cs:line 10
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.g__Core|5_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Carmen.Position.Infrastructure.EmtInterface.Repository.EmtAuctionResultServiceClient.<>c__DisplayClass2_0.<b__0>d.MoveNext() in /home/vsts/work/1/s/backend/src/Infrastructure/EmtInterface/Repository/EmtAuctionResultServiceClient.cs:line 27

Relevant code snippets

Our Token Aquisition
#
public class DownstreamApiTokenAcquisitionHandler(ITokenAcquisition acquisition, string appScope) : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var accessToken = await acquisition.GetAccessTokenForAppAsync(appScope);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        return await base.SendAsync(request, cancellationToken);
    }
}

Handler registration

    public static IHttpClientBuilder AddDownstreamApiTokenAcquisitionHandler(this IHttpClientBuilder builder, Func<IServiceProvider, string> appScopeFunc)
    {
        return builder.AddHttpMessageHandler(
            provider =>
            {
                var appScope = appScopeFunc(provider);
                return ActivatorUtilities.CreateInstance<DownstreamApiTokenAcquisitionHandler>(provider, appScope);
            });
    }

Together with HttpClientFactory

        services.AddHttpClient<TInterface, TClient>(
                (serviceProvider, client) =>
                {
                    var optionsFactory = serviceProvider.GetRequiredService<IOptionsMonitor<DownstreamApiOptions>>();
                    var options = optionsFactory.Get(serviceName);
                    client.BaseAddress = new Uri(options.BaseUrl!);
                })
            .AddDownstreamApiTokenAcquisitionHandler(
                provider =>
                {
                    var optionsFactory = provider.GetRequiredService<IOptionsMonitor<DownstreamApiOptions>>();
                    var options = optionsFactory.Get(serviceName);
                    var appScope = options.Scopes?.SingleOrDefault(s => s.StartsWith("api://", StringComparison.Ordinal));
                    return appScope ?? throw new InvalidOperationException($"Missing a api//* Scope for {serviceName}");
                })
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { UseProxy = false });


### Expected behavior

Just work as in 4.61.0.... or find the problem 

### Identity provider

Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)

### Regression

4.61.0

### Solution and workarounds

Downgrade to 4.61.0 resolved the problem.

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