Logout from a Blazor server app with multiple open browser tabs

Viewed 31

I'm working on a Blazor server application with Identity, and I have some doubts about security.

In a situation when the user opens multiple browser tabs and then logs out in one, all other tabs still consider user authorized. The application can be used until the next page refresh.

As I understood from the documentation on AuthenticationStateProvider, it works only in the current circuit, and it can't see the user logged out in another tab.

Is there a way to inform other tabs that the user is logged out?

1 Answers

After some digging, it turned out that the basic template has an almost complete solution.

In the Identity folder there is a class named RevalidatingIdentityAuthenticationStateProvider. It extends RevalidatingServerAuthenticationStateProvider in a way that it checks if an identity SecurityStamp is modified and updates AuthenticationState.

The problem with the template is that SecurityStamp is never modified - it is created when the user logs in and doesn't change.

1. Update security stamp in logout

To update the authentication state, the security stamp should be updated when the user logs out in any tab. This is done in the Logout.cshtml .

@page
@using Microsoft.AspNetCore.Identity
@attribute [IgnoreAntiforgeryToken]
@inject  SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@functions{
    public async Task<IActionResult> OnGet()
    {
        if(SignInManager.IsSignedIn(User))
        {
            await SignInManager.SignOutAsync();
            //add this to update security stamp
            var identity = await UserManager.FindByEmailAsync(User.Identity.Name);
            await UserManager.UpdateSecurityStampAsync(identity);
        }
        return Redirect("~/");
    }
}

2. Revalidation interval

Class RevalidatingIdentityAuthenticationStateProvider contains property

protected override TimeSpan RevalidationInterval => TimeSpan.FromSeconds(30);

This property defines the interval between two authentication state checks.

The problem with this property is that by default, it is set to 30 minutes. To be useful, in my opinion, the interval should be way shorter.

3. Logout on other tabs

  • components that are wrapped in the AuthorizeView component will automatically switch to NotAuthorized after revalidation triggers

  • if app contains code that needs information about authorization status, it an be checked like this:

    [CascadingParameter]
    public Task<AuthenticationState> AuthenticationStateTask { get; set; }
    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateTask;
        var user = authState.User;
    
        if (user.Identity.IsAuthenticated)
        {
            // do something for authenticated users
        }
        else{
            // do something when the user is not authenticated 
        }
    }
    

Potential problem

  • above solution uses authentication state polling based on the timer. Depending on the number of users and length of the interval, this might cause performance issues
  • a solution that notifies authentication state providers across the circuits would be "nicer"

Current result

  • test revalidation interval is set to 30 seconds.
  • when a single user opens an application in multiple tabs and then logs out from the application in one of the tabs, the user is automatically logged out from the application in all other tabs in a max of 30 seconds.

This looks fine, but it still lacks a performance test with a high number of users.

Related