microsoft-authentication-library-for-dotnet
microsoft-authentication-library-for-dotnet copied to clipboard
[Bug] GetAccount returns null in AuthCode flow in ASP.NET OWIN app
Logs and network traces Error Code: user_null Error Message: No account or login hint was passed to the AcquireTokenSilent call. I have also noticed that this happens under the following scenarios:
Which version of MSAL.NET are you using? MSAL.NET 4.46.1.0
Platform .NET 4.8
What authentication flow has the issue?
- Desktop / Mobile
- [ ] Interactive
- [ ] Integrated Windows Authentication
- [ ] Username Password
- [ ] Device code flow (browserless)
- Web app
- [x] Authorization code
- [ ] On-Behalf-Of
- Daemon app
- [x] Service to Service calls
Other?
Is this a new or existing app? a. The app is in production, and I have upgraded to a new version of MSAL.
Repro
public async Task<string> GetAccessTokenAsync()
{
string accessToken;
UserExternalApp.Scope = string.IsNullOrWhiteSpace(UserExternalApp.Scope) ? "" : UserExternalApp.Scope;
// Load the app config from web.config
var microsoftScopes = UserExternalApp.Scope.Replace(' ', ',').SplitAndTrim(new char[] { ',' }).ToList();
var accountID = UserExternalApp.ExternalUserAccountID;
var app = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithRedirectUri(DefaultRedirectUrl) // https:\//mywebsite.com
.WithClientSecret(Secret)
.Build();
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
try
{
var account = await app.GetAccountAsync(accountID);
var query = app.AcquireTokenSilent(microsoftScopes, account); // This is where the error is thrown
var acquireTokenSilent = await query.ExecuteAsync();
accessToken = acquireTokenSilent.AccessToken;
}
catch
{
// This is the error thrown:
// Exception Type: MsalUiRequiredException
// Error code: user_null
// Exception Details: No account or login hint was passed to the AcquireTokenSilent call.
throw;
}
return accessToken;
}
Expected behavior A valid account should be provided by GetAccountAsync(). Using this, AcquireTokenSilent() should get the access token
Actual behavior Account returned by GetAccountAsync() is null. As a result, subsequent call to AcquireTokenSilent() fails.
Update
I resolved this particular issue by creating an implementation of IAccount and populating the homeAccountId
field. Interestingly, in my case, the above error went away when I implemented this workaround. I feel that this is a bug that the team should investigate.
@alfaromeo90210 Sorry for the late reply. In your workaround do you set homeAccountId
to UserExternalApp.ExternalUserAccountID
or how do you construct it?
Is your app multi tenant? MSAL needs the home tenant of the user, so for guest accounts, if you pass tenant id of that guest tenant, then MSAL won't find the account in the cache.
For reference, there's this PR that shows how get the home account id by passing the client_info flag.
Closing as duplicate of https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/3642 - see workarounds there.