microsoft-authentication-library-for-dotnet: [Bug] NullReferenceException from MSAL when using region with CCA

Logs and network traces CorrelationId == “a95592bb-f6c4-4f96-8e09-1ed652ec76fd”

Which version of MSAL.NET are you using? 4.35.1.0

Platform

What authentication flow has the issue?

  • Desktop / Mobile
    • Interactive
    • Integrated Windows Authentication
    • Username Password
    • Device code flow (browserless)
  • Web app
    • Authorization code
    • On-Behalf-Of
  • Daemon app
    • Service to Service calls

Other?

Is this a new or existing app? Upgrade to MSAL

Repro Create CCA

//Create CCA
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(ClientId)
    .WithCertificate(Cert)
    .WithAzureRegion(msalRegion)
    .WithLegacyCacheCompatibility(false)
    .WithLogging(this.LogMSALMessages, Microsoft.Identity.Client.LogLevel.Warning)
    .Build();

//Acquire Token
var authenticationResult = await this.GetConfidentialClientApplication()
    .AcquireTokenForClient(scopes)
    .WithAuthority($"https://login.microsoft.com/{tenantId}")) // this is the root cause of the failure
    .WithSendX5C(sendX5c)
    .ExecuteAsync()
    .ConfigureAwait(false);

Expected behavior MSAL should acquire a token

Actual behavior Null Ref

System.NullReferenceException : Object reference not set to an instance of an object. at Microsoft.Identity.Client.Region.RegionManager.IsTelemetryRecorded(ApiEvent apiEvent) at Microsoft.Identity.Client.Region.RegionManager.RecordTelemetry(ApiEvent apiEvent, String azureRegionConfig, RegionInfo discoveredRegion) …

Root cause

MSAL tries to validate that the authority at the request level is the same as the authority at the app level. Since the hosts differ, it tries to do instance discovery to find out aliases. There is no api event, so this fails.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (13 by maintainers)

Commits related to this issue

Most upvoted comments

I think we’re at a point where we can’t support WithAuthority at the request level anymore. It’s just too complex to handle all validation scenarios, aliasing and regionalization.

We should deprecate this method and provide the WithTenant instead, which is really what ppl want to do anyway. Along with deprecation, we will throw an exception if both authority override and regional are used, something like “Please use WithTenant instead, WithAuthority at the request level is not compatible with WithRegional”.

My only question is … what is the equivalent for B2C? What should we do there? Do we really want to change the tenant? I think not.

Workaround of this issue:

  • this happens only if the authority host at the app level (which defaults to “login.microsoftonline.com”) is different than the authority at the request level.
  • so the workaround is to ensure they are always the same. For example:
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(ClientId)
    .WithCertificate(Cert)
    .WithAuthority("https://login.microsoftonline.com/common") // use whatever tenant ID you want here
    .Build();

//Acquire Token
var authenticationResult = await this.GetConfidentialClientApplication()
    .AcquireTokenForClient(scopes)
    .WithAuthority($"https://login.microsoftonline.com/{tenantId}")) // the host must be the same! 
    .ExecuteAsync()
    .ConfigureAwait(false);

Note: if reading the authority from a WWWAuthenticateHeader, it can be “login.windows.net” or “login.microsoft.com”

@bgavrilMS assuming withregion and withtenantid would work fine

@henrik-me, was thinking of a soft deprecation, something like:

  • Obsolete (warning only) against request.WithAuthority but continue to support it
  • if both request.WithAuthority and app.WithRegion are used, throw an exception.