From f148ccdeba3d3ef9d050c65560ad8200582e2dfa Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Sat, 31 May 2025 08:46:35 +0200 Subject: [PATCH] Add revoke all option to admin user refresh tokens (#874) --- .../View/Components/RefreshTokenTable.razor | 27 +++++++++++++++++++ .../Main/Pages/Users/View/Index.razor | 20 ++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/apps/server/AliasVault.Admin/Main/Pages/Users/View/Components/RefreshTokenTable.razor b/apps/server/AliasVault.Admin/Main/Pages/Users/View/Components/RefreshTokenTable.razor index 49796e568..76228decd 100644 --- a/apps/server/AliasVault.Admin/Main/Pages/Users/View/Components/RefreshTokenTable.razor +++ b/apps/server/AliasVault.Admin/Main/Pages/Users/View/Components/RefreshTokenTable.razor @@ -1,5 +1,9 @@ @using AliasVault.RazorComponents.Tables +
+ +
+ @foreach (var entry in SortedRefreshTokenList) { @@ -29,6 +33,12 @@ [Parameter] public EventCallback OnRevokeToken { get; set; } + /// + /// Gets or sets the event callback to revoke all refresh tokens. + /// + [Parameter] + public EventCallback OnRevokeAllTokens { get; set; } + private string SortColumn { get; set; } = "CreatedAt"; private SortDirection SortDirection { get; set; } = SortDirection.Descending; @@ -67,4 +77,21 @@ { await OnRevokeToken.InvokeAsync(entry); } + + private async Task RevokeAllTokens() + { + if (await ConfirmModalService.ShowConfirmation( + title: "Confirm Revoke All Tokens", + message: @"Are you sure you want to revoke all refresh tokens? + +Important notes: +• This will log out the user from all their devices. +• They will need to log in again on each device. +• This action cannot be undone. + +Do you want to proceed with revoking all tokens?")) + { + await OnRevokeAllTokens.InvokeAsync(); + } + } } diff --git a/apps/server/AliasVault.Admin/Main/Pages/Users/View/Index.razor b/apps/server/AliasVault.Admin/Main/Pages/Users/View/Index.razor index f389b78f0..7f6e28db1 100644 --- a/apps/server/AliasVault.Admin/Main/Pages/Users/View/Index.razor +++ b/apps/server/AliasVault.Admin/Main/Pages/Users/View/Index.razor @@ -96,7 +96,7 @@ else

UserRefreshTokens (Logged in devices)

- +
@@ -327,7 +327,7 @@ Do you want to proceed with the restoration?")) { { User.Blocked = !User.Blocked; - // If user is unblocked by the admin, also reset any lockout status, which can be + // If user is unblocked by the admin, also reset any lockout status, which can be // automatically triggered by the system when user has entered an incorrect password too many times. if (!User.Blocked) { User.AccessFailedCount = 0; @@ -338,4 +338,20 @@ Do you want to proceed with the restoration?")) { await RefreshData(); } } + + /// + /// This method will revoke all refresh tokens for the user which will log out all their devices. + /// + private async Task RevokeAllTokens() + { + await using var dbContext = await DbContextFactory.CreateDbContextAsync(); + var tokens = await dbContext.AliasVaultUserRefreshTokens.Where(x => x.UserId == User!.Id).ToListAsync(); + + if (tokens.Any()) + { + dbContext.AliasVaultUserRefreshTokens.RemoveRange(tokens); + await dbContext.SaveChangesAsync(); + await RefreshData(); + } + } }