Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] ITokenAcquisition.GetAccessTokenForUserAsync throws MsalUiRequiredException exception running second time #588

Closed
1 of 7 tasks
damienbod opened this issue Sep 17, 2020 · 3 comments
Labels
answered duplicate This issue or pull request already exists question Further information is requested

Comments

@damienbod
Copy link

damienbod commented Sep 17, 2020

When running a Web APP which uses an API, the ITokenAcquisition.GetAccessTokenForUserAsync method throws an exception when running the second time after stopping the application. This is probably because the cookies are valid, but the in-memeory cache is empty because the application was restarted.

The GetAccessTokenForUserAsync should not throw an exception if it has no token, but get a new one. At present, this is not a good development experience. If I delete my cookies, then the app logs in again and then gets a new token.

Which version of Microsoft Identity Web are you using?
0.4.0-preview

Where is the issue?

  • Web app
    • Sign-in users
    • [] 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
    • In-memory caches
    • Session caches
    • Distributed caches
  • Other (please describe)

Is this a new or an existing app?
c. This is a new app or an experiment.

Expected behavior
No Exception when it runs a second time

Repro

Code: https://github.com/damienbod/AzureAD-Auth-MyUI-with-MyAPI

public void ConfigureServices(IServiceCollection services)
{

	//...

	services.AddMicrosoftIdentityWebApiAuthentication(Configuration);

	services.AddControllers(options =>
	{
		var policy = new AuthorizationPolicyBuilder()
			.RequireAuthenticatedUser()
		   // .RequireClaim("email") // disabled this to test with users that have no email (no license added)
			.Build();
		options.Filters.Add(new AuthorizeFilter(policy));
	});
}
var client = _clientFactory.CreateClient();

var scope = _configuration["CallApi:ScopeForAccessToken"];
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { scope });

client.BaseAddress = new Uri(_configuration["CallApi:ApiBaseAddress"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var response = await client.GetAsync("weatherforecast");
if (response.IsSuccessStatusCode)
{
	var responseContent = await response.Content.ReadAsStringAsync();
	var data = JArray.Parse(responseContent);

	return data;
}

Actual behavior

An unhandled exception occurred while processing the request.
ApplicationException: Exception Microsoft.Identity.Web.MicrosoftIdentityWebChallengeUserException: IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent.
---> MSAL.NetCore.4.18.0.0.MsalUiRequiredException:
ErrorCode: user_null
Microsoft.Identity.Client.MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.
at Microsoft.Identity.Client.AcquireTokenSilentParameterBuilder.Validate()
at Microsoft.Identity.Client.AbstractAc

Greetings Damien

@jmprieur
Copy link
Collaborator

@damienbod : Thanks for the feedback. You are right that there is a session cookie, but no access token in the cache, because you are using the In memory token cache (the default from the templates) and this cache is emptied when stopping the app.
If you were using another form of token cache serialization the user could be re-logged-in.

We recommend handling the exception by using the AuthorizeForScopes attribute in controllers or Razor pages, and the MicrosoftIdentityConsentAndConditionalAccessHandler in Blazor apps. For details, see https://github.com/AzureAD/microsoft-identity-web/wiki/Managing-incremental-consent-and-conditional-access.

@onovotny raised an issue about that: Should clear session auth cookie if cache is missing account #13, but other customers told us they prefer the current behavior where the user remains signed in, and MSAL requires a token.

Happy to have a discussion with you, @jennyf19 and @onovotny
Maybe we should have a boolean option in MicrosoftIdentityOptions to control the behavior?

any feedback is welcome.

@jmprieur jmprieur added answered duplicate This issue or pull request already exists question Further information is requested labels Sep 17, 2020
@damienbod
Copy link
Author

@jmprieur Thanks for the feedback. This means in-memory cache cannot be used for production in this setup. I usually check if I have a token, or it is expired and get another then if required. I would welcome the bool very much. I will close this then and move to the other issue.

@jmprieur
Copy link
Collaborator

Thanks @damienbod
Yes, in production you probably want to use another token cache serialization: For details, see https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
answered duplicate This issue or pull request already exists question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants