question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Bug] : NullReferenceException when acquiring a token for a user in a server-side Blazor app.

See original GitHub issue

Which Version of Microsoft Identity Web are you using ? Microsoft Identity Web 0.1.2-preview

Where is the issue?

  • Web App
    • Sign-in users
    • [ X] Sign-in users and call web APIs
  • Web API
    • Protected web APIs (Validating tokens)
    • Protected web APIs (Validating scopes)
    • Protected web APIs call downstream web APIs
  • Token cache serialization
    • [X ] In Memory caches
    • Session caches
    • Distributed caches

This is a new application that is a server-side Razor application calling a protected Web API. The application works as expected locally, but fails with a NullReferenceException when running as an Azure App Service. The failure occurs when trying to retrieve a token for a user (GetAccessTokenForUserAsync). The request to get a token for the user occurs in a lower-level HttpClient service when retrieving the token to add as an Authorization header. The HttpClient service is injected into the Blazor page (@inject). As a test, I’ve added code to the OnGet() method of the Blazor page (which runs on first access of a page from the site), and the same code works as expected both locally and in Azure (GetAccessTokenForUserAsync returns a valid token with no exception).

I have confirmed that the following values are correctly configured:

  • TenantId
  • ClientId
  • ClientSecret

I have confirmed the application has been registered correctly in Azure AD with valid value(s) for:

  • RedirectURIs
  • Scopes

Given I can run the application locally with no exceptions, I don’t think I have missing or invalid configuration. I also don’t think this issue has anything to do with the Web API itself, this exception occurs simply trying to get a token from the cache and/or from MSAL prior to communication with the (protected) Web API.

Repro

Startup.cs

services
	.AddSignIn(
		openIdOptions => Configuration.Bind("AppAzureAd", openIdOptions),
		identityOptions => Configuration.Bind("AppAzureAd", identityOptions)
	)
	.AddWebAppCallsProtectedWebApi(
		Configuration.GetSection("Api:Scopes").Get<List<string>>(),
		openIdOptions => Configuration.Bind("AppAzureAd", openIdOptions),
		identityOptions =>
		{
			Configuration.Bind("AppAzureAd", identityOptions);
			identityOptions.EnablePiiLogging = environment.IsDevelopment();
		}
	)
	.AddInMemoryTokenCaches()
	.AddTokenAcquisition();

Blazor Page method that works as expected (no exceptions, token acquired) on first page request:

public async Task<IActionResult> OnGet()
{
	if (!User.Identity.IsAuthenticated)
		return Challenge();

	try
	{
		var token = await tokenAcquisition.GetAccessTokenForUserAsync(apiOptions.Value.Scopes);
	}
	catch (MsalUiRequiredException ex)
	{
		//can't get a token from the token store, MUST assume a sign-out path as requests to API will NOT be authenticated
		logger.LogError(ex, ex.Message);
		await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
		return Challenge();
	}

	return Page();
}

HttpClient setting the authorization header (GetAccessTokenForUserAsync works locally, but fails in Azure):

private async Task AddAuthorizationHeaderAsync(HttpRequestMessage request)
{
	request.Headers.Authorization = new AuthenticationHeaderValue(JwtBearerDefaults.AuthenticationScheme, await AcquireTokenAsync());
}

private async Task<string> AcquireTokenAsync()
{
	string token;
	try
	{
		token = await tokenAcquisition.GetAccessTokenForUserAsync(apiOptions.Value.Scopes);
	}
	catch (MsalUiRequiredException ex)
	{
		//can't get a token from the token store, MUST assume a sign-out path as requests to API will NOT be authenticated
		logger.LogError(ex, ex.Message);
		throw;
	}

	return token;
}

Expected behavior I expect to be able to acquire a valid token for the user at any point during the “request” lifecycle.

Actual behavior The following stack trace:

[2020-05-12T21:55:47.258Z] Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Identity.Web.TokenAcquisition.CreateRedirectUri()
   at Microsoft.Identity.Web.TokenAcquisition.BuildConfidentialClientApplicationAsync()
   at Microsoft.Identity.Web.TokenAcquisition.GetOrBuildConfidentialClientApplicationAsync()
   at Microsoft.Identity.Web.TokenAcquisition.GetAccessTokenForUserAsync(IEnumerable`1 scopes, String tenant)
   ...

Possible Solution At a minimum, better exception handling that leads me to the actual error.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:25 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
dansmittcommented, Jul 23, 2020

@jennyf19 sounds good to me! Thx for the support 💪🏻

2reactions
jennyf19commented, Jul 22, 2020

@gwgrubbs & @schmid37 glad to hear it’s working, thanks for confirming. we are aware of the redirect issue, it’s because blazor doesn’t have the challenge method, so we’re trying to come up with a work around.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why is the returned access token null in a Blazor Server ...
I have a Blazor application (Server-Side) running on .net6 . It is connected to my Azure Active Directory. I can successfully authenticate ...
Read more >
why this error generated on blazor and how to solve it
I work on blazor app server side . i found my app stuck i don't kno ... NullReferenceException: Object reference not set to...
Read more >
ASP.NET Core Blazor SignalR guidance
Learn how to configure and manage Blazor SignalR connections.
Read more >
Authentication with client-side Blazor using WebAPI and ...
In this post, I show how you can build a client-side Blazor app with authentication using WebAPI and ASP.NET Core Identity.
Read more >
Custom Authentication in Blazor WebAssembly - Step-By- ...
In this tutorial, we will go by using Microsoft Identity. You could switch this with your own logic if needed. Let's a mode...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found