Home > Net >  MSAL not storing token in cache
MSAL not storing token in cache

Time:06-01

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();
  • Related