This is the code:
using Microsoft.Identity.Client;
var scopes = new string[] { "user.read" };
var clientId = "4a1aa1d5-c567-49d0-ad0b-cd957a47f842";
var tenant = "common";
var authority = "https://login.microsoftonline.com/" tenant;
IPublicClientApplication publicClientApp;
AuthenticationResult authResult;
publicClientApp = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.WithRedirectUri("http://localhost:8080")
.Build();
var accounts = await publicClientApp
.GetAccountsAsync()
.ConfigureAwait(false);
IAccount? firstAccount = accounts.FirstOrDefault();
authResult = await publicClientApp
.AcquireTokenInteractive(new string[] { "user.read" })
.ExecuteAsync()
.ConfigureAwait(false);
authResult = await publicClientApp
.AcquireTokenSilent(new string[] { "user.read" }, firstAccount)
.ExecuteAsync();
This is the exception that is being thrown:
Unhandled exception. MSAL.NetCore.4.44.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.Internal.Requests.Silent.SilentRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.Silent.SilentRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.ClientApplicationBaseExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenSilentParameters silentParameters, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in /home/adrian/temp/microsoft-identity-platform/simpler-version-public/Program.cs:line 25
at Program.<Main>(String[] args)
StatusCode: 0
ResponseBody:
Headers:
The csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>simpler_version_public</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Identity.Client" Version="4.44.0" />
</ItemGroup>
</Project>
My understanding is that calling AcquireTokenInteractive()
should automatically store the token in the cache, and AcquireTokenSilent()
gets the token from the cache. Why am I getting the error then? I am running this code in WSL, and dotnet --version
returns 6.0.300
.
CodePudding user response:
You call GetAccountsAsync
before AcquireTokenInteractive
and it doesn't return any account. No account is passed to AcquireTokenSilent
and this method doesn't know for which account should be access token acquired.
You need to call GetAccountsAsync
after you call AcquireTokenInteractive
. In that case it will return the account and AcquireTokenSilent
will acquire the token from the cache for the specified account.
authResult = await publicClientApp
.AcquireTokenInteractive(new string[] { "user.read" })
.ExecuteAsync()
.ConfigureAwait(false);
var accounts = await publicClientApp
.GetAccountsAsync()
.ConfigureAwait(false);
IAccount? firstAccount = accounts.FirstOrDefault();
authResult = await publicClientApp
.AcquireTokenSilent(new string[] { "user.read" }, firstAccount)
.ExecuteAsync();