Home > Back-end >  MSAL.NET redirect loop when using graphApi in MVC & blazor with multiple instances
MSAL.NET redirect loop when using graphApi in MVC & blazor with multiple instances

Time:08-18

I have created a blazor component that aims to simplify managing users and group of an enterprise application in my ASP.NET MVC website. When I run the code locally, everything works just fine. However, when I deploy my code on the dev environment (in AKS) the code only works if I run one replica.

When I use multiple instances and I try to access the page that calls my blazor component, the page ends up in a redirect loop, and finally shows the Microsoft login interface with an error mentioning that the login was not valid.

This is how my code looks like:

# program.cs
var initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
var cacheOptions = builder.Configuration.GetSection("AzureTableStorageCacheOptions").Get<AzureTableStorageCacheOptions>();

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
    .AddDistributedTokenCaches();

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24);
});

builder.Services.AddDistributedAzureTableStorageCache(options =>
{
    options.ConnectionString = cacheOptions.ConnectionString;
    options.TableName = cacheOptions.TableName;
    options.PartitionKey = cacheOptions.PartitionKey;
    options.CreateTableIfNotExists = true;
    options.ExpiredItemsDeletionInterval = TimeSpan.FromHours(24);
});

builder.Services.AddSession();

...
# The controller that calls the blazor component
[AuthorizeForScopes(Scopes = new[] { "Application.ReadWrite.All", "Directory.Read.All", "Directory.ReadWrite.All" })]
public async Task<IActionResult> UserManagement()
    {
        string[] scopes = new string[] { "Application.ReadWrite.All", "Directory.Read.All", "Directory.ReadWrite.All" };
        try
        {
            await _tokenAcquisition
                .GetAccessTokenForUserAsync(scopes)
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            _telemetryClient.TrackException(ex);
        }
        return View();
    }

And this is what happens:

enter image description here enter image description here

If the page loads, I can see this exception in the pod logs:

enter image description here

What am I doing wrong?

CodePudding user response:

So, the culprit was:

#my controller
    await _tokenAcquisition
                .GetAccessTokenForUserAsync(scopes)
                .ConfigureAwait(false);

Which we were using initially to reauthenticate the graph api component when we were using InMemoryCache.

There is no need to get the access token again when using DistributedTokenCache, and actually that was causing the token to get saved / invalidated in an infinite loop.

More on that: enter image description here

Also as a work around try to use use httpContextAccessor to access token after authentication .

Reference: c# - Error : No account or login hint was passed to the AcquireTokenSilent call - Stack Overflow

  • Related