public class RevalidatingAuthenticationStateProvider : AuthenticationStateProvider, IDisposable { private static TimeSpan RefreshInterval = TimeSpan.FromMinutes(30); private readonly CancellationTokenSource _cts; private ClaimsPrincipal _currentUser; public RevalidatingAuthenticationStateProvider(SignInManager signInManager) { _cts = new CancellationTokenSource(); _currentUser = signInManager.Context.User; _ = RefreshLoop(_cts.Token, signInManager); } private async Task RefreshLoop(CancellationToken cancellationToken, SignInManager signInManager) { while (true) { await Task.Delay(RefreshInterval, cancellationToken); if (cancellationToken.IsCancellationRequested) { break; } try { // Rebuild user data using latest info from Identity DB var identityUser = await signInManager.UserManager.GetUserAsync(_currentUser); _currentUser = await signInManager.CreateUserPrincipalAsync(identityUser); } catch { // If anything goes wrong, just log them out _currentUser = new ClaimsPrincipal(); _cts.Cancel(); } NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } } public override Task GetAuthenticationStateAsync() => Task.FromResult(new AuthenticationState(_currentUser)); public void Dispose() => _cts.Cancel(); }