Skip to content

Commit 5f2de3a

Browse files
committed
Complete Logout & Revoke Semantics & Added Tests
1 parent 2e826f7 commit 5f2de3a

File tree

49 files changed

+1202
-365
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1202
-365
lines changed

samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,6 @@
2323
</MudDialog>
2424

2525
@code {
26-
27-
private MudForm? _form;
28-
29-
private string? _firstName;
30-
private string? _lastName;
31-
private string? _displayName;
32-
33-
private DateTime? _birthDate;
34-
private string? _gender;
35-
private string? _bio;
36-
37-
private string? _language;
38-
private string? _timeZone;
39-
private string? _culture;
40-
4126
[CascadingParameter]
4227
private IMudDialogInstance MudDialog { get; set; } = default!;
4328

samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor

Lines changed: 248 additions & 41 deletions
Large diffs are not rendered by default.

src/CodeBeam.UltimateAuth.Client/AuthState/UAuthStateEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ public enum UAuthStateEvent
1111
RolesChanged,
1212
PermissionsChanged,
1313
SessionRevoked,
14-
UserDeleted
14+
UserDeleted,
15+
LogoutVariant
1516
}

src/CodeBeam.UltimateAuth.Client/AuthState/UAuthStateManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private async Task HandleStateEvent(UAuthStateEventArgs args)
8080
return;
8181
}
8282

83-
if (args.Type == UAuthStateEvent.CredentialsChanged || args.Type == UAuthStateEvent.UserDeleted)
83+
if (args.Type == UAuthStateEvent.CredentialsChanged || args.Type == UAuthStateEvent.UserDeleted || args.Type == UAuthStateEvent.LogoutVariant)
8484
{
8585
State.Clear();
8686
return;

src/CodeBeam.UltimateAuth.Client/Services/Abstractions/IFlowClient.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using CodeBeam.UltimateAuth.Client.Contracts;
22
using CodeBeam.UltimateAuth.Core.Contracts;
3+
using CodeBeam.UltimateAuth.Core.Domain;
4+
using CodeBeam.UltimateAuth.Users.Contracts;
35

46
// TODO: Add ReauthAsync
57
namespace CodeBeam.UltimateAuth.Client.Services;
@@ -14,4 +16,11 @@ public interface IFlowClient
1416

1517
Task BeginPkceAsync(string? returnUrl = null);
1618
Task CompletePkceLoginAsync(PkceLoginRequest request);
19+
20+
Task<UAuthResult<RevokeResult>> LogoutDeviceSelfAsync(LogoutDeviceSelfRequest request);
21+
Task<UAuthResult> LogoutOtherDevicesSelfAsync();
22+
Task<UAuthResult> LogoutAllDevicesSelfAsync();
23+
Task<UAuthResult<RevokeResult>> LogoutDeviceAdminAsync(UserKey userKey, SessionChainId chainId);
24+
Task<UAuthResult> LogoutOtherDevicesAdminAsync(LogoutOtherDevicesAdminRequest request);
25+
Task<UAuthResult> LogoutAllDevicesAdminAsync(UserKey userKey);
1726
}

src/CodeBeam.UltimateAuth.Client/Services/Abstractions/ISessionClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface ISessionClient
1313

1414

1515
Task<UAuthResult<PagedResult<SessionChainSummaryDto>>> GetUserChainsAsync(UserKey userKey);
16-
Task<UAuthResult<SessionChainDetailDto>> GetUserChainAsync(UserKey userKey, SessionChainId chainId);
16+
Task<UAuthResult<SessionChainDetailDto>> GetUserChainDetailAsync(UserKey userKey, SessionChainId chainId);
1717
Task<UAuthResult> RevokeUserSessionAsync(UserKey userKey, AuthSessionId sessionId);
1818
Task<UAuthResult> RevokeUserChainAsync(UserKey userKey, SessionChainId chainId);
1919
Task<UAuthResult> RevokeUserRootAsync(UserKey userKey);

src/CodeBeam.UltimateAuth.Client/Services/UAuthFlowClient.cs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using CodeBeam.UltimateAuth.Core.Contracts;
99
using CodeBeam.UltimateAuth.Core.Domain;
1010
using CodeBeam.UltimateAuth.Core.Infrastructure;
11+
using CodeBeam.UltimateAuth.Users.Contracts;
1112
using Microsoft.AspNetCore.Components;
1213
using Microsoft.Extensions.Options;
1314
using System.Net;
@@ -234,6 +235,65 @@ public async Task CompletePkceLoginAsync(PkceLoginRequest request)
234235
await _post.NavigateAsync(url, payload);
235236
}
236237

238+
public async Task<UAuthResult<RevokeResult>> LogoutDeviceSelfAsync(LogoutDeviceSelfRequest request)
239+
{
240+
var raw = await _post.SendJsonAsync(Url($"/logout-device"), request);
241+
242+
if (raw.Ok)
243+
{
244+
var result = UAuthResultMapper.FromJson<RevokeResult>(raw);
245+
246+
if (result.Value?.CurrentChain == true)
247+
{
248+
await _events.PublishAsync(new UAuthStateEventArgsEmpty(UAuthStateEvent.LogoutVariant, _options.UAuthStateRefreshMode));
249+
}
250+
251+
return result;
252+
}
253+
254+
return UAuthResultMapper.FromJson<RevokeResult>(raw);
255+
}
256+
257+
public async Task<UAuthResult<RevokeResult>> LogoutDeviceAdminAsync(UserKey userKey, SessionChainId chainId)
258+
{
259+
LogoutDeviceAdminRequest request = new() { UserKey = userKey, ChainId = chainId };
260+
var raw = await _post.SendJsonAsync(Url($"/admin/users/logout-device/{userKey.Value}"), request);
261+
return UAuthResultMapper.FromJson<RevokeResult>(raw);
262+
}
263+
264+
public async Task<UAuthResult> LogoutOtherDevicesSelfAsync()
265+
{
266+
var raw = await _post.SendJsonAsync(Url("/logout-others"));
267+
return UAuthResultMapper.From(raw);
268+
}
269+
270+
public async Task<UAuthResult> LogoutOtherDevicesAdminAsync(LogoutOtherDevicesAdminRequest request)
271+
{
272+
var raw = await _post.SendJsonAsync(Url($"/admin/users/logout-others/{request.UserKey.Value}"), request);
273+
return UAuthResultMapper.From(raw);
274+
}
275+
276+
public async Task<UAuthResult> LogoutAllDevicesSelfAsync()
277+
{
278+
var raw = await _post.SendJsonAsync(Url("/logout-all"));
279+
if (raw.Ok)
280+
{
281+
await _events.PublishAsync(new UAuthStateEventArgsEmpty(UAuthStateEvent.LogoutVariant, _options.UAuthStateRefreshMode));
282+
}
283+
return UAuthResultMapper.From(raw);
284+
}
285+
286+
public async Task<UAuthResult> LogoutAllDevicesAdminAsync(UserKey userKey)
287+
{
288+
var raw = await _post.SendJsonAsync(Url($"/admin/users/logout-all/{userKey.Value}"));
289+
if (raw.Ok)
290+
{
291+
await _events.PublishAsync(new UAuthStateEventArgsEmpty(UAuthStateEvent.LogoutVariant, _options.UAuthStateRefreshMode));
292+
}
293+
return UAuthResultMapper.From(raw);
294+
}
295+
296+
237297
private Task NavigateToHubLoginAsync(string authorizationCode, string codeVerifier, string returnUrl)
238298
{
239299
var hubLoginUrl = Url(_options.Endpoints.HubLoginPath);
@@ -249,9 +309,6 @@ private Task NavigateToHubLoginAsync(string authorizationCode, string codeVerifi
249309
return _post.NavigateAsync(hubLoginUrl, data);
250310
}
251311

252-
253-
// ---------------- PKCE CRYPTO ----------------
254-
255312
private static string CreateVerifier()
256313
{
257314
var bytes = RandomNumberGenerator.GetBytes(32);

src/CodeBeam.UltimateAuth.Client/Services/UAuthSessionClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<UAuthResult<RevokeResult>> RevokeMyChainAsync(SessionChainId c
4242
var raw = await _request.SendJsonAsync(Url($"/session/me/chains/{chainId}/revoke"));
4343
var result = UAuthResultMapper.FromJson<RevokeResult>(raw);
4444

45-
if (result.Value?.CurrentSessionRevoked == true)
45+
if (result.Value?.CurrentChain == true)
4646
{
4747
await _events.PublishAsync(new UAuthStateEventArgsEmpty(UAuthStateEvent.SessionRevoked, _options.UAuthStateRefreshMode));
4848
}
@@ -76,7 +76,7 @@ public async Task<UAuthResult<PagedResult<SessionChainSummaryDto>>> GetUserChain
7676
return UAuthResultMapper.FromJson<PagedResult<SessionChainSummaryDto>>(raw);
7777
}
7878

79-
public async Task<UAuthResult<SessionChainDetailDto>> GetUserChainAsync(UserKey userKey, SessionChainId chainId)
79+
public async Task<UAuthResult<SessionChainDetailDto>> GetUserChainDetailAsync(UserKey userKey, SessionChainId chainId)
8080
{
8181
var raw = await _request.SendFormAsync(Url($"/admin/users/{userKey}/sessions/chains/{chainId}"));
8282
return UAuthResultMapper.FromJson<SessionChainDetailDto>(raw);

src/CodeBeam.UltimateAuth.Core/Abstractions/Stores/ISessionStore.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ public interface ISessionStore
1212
Task SaveSessionAsync(UAuthSession session, long expectedVersion, CancellationToken ct = default);
1313
Task CreateSessionAsync(UAuthSession session, CancellationToken ct = default);
1414
Task<bool> RevokeSessionAsync(AuthSessionId sessionId, DateTimeOffset at, CancellationToken ct = default);
15+
public Task RevokeOtherSessionsAsync(UserKey user, SessionChainId keepChain, DateTimeOffset at, CancellationToken ct = default);
16+
public Task RevokeAllSessionsAsync(UserKey user, DateTimeOffset at, CancellationToken ct = default);
17+
Task RemoveSessionAsync(AuthSessionId sessionId, CancellationToken ct = default);
1518

1619
Task<UAuthSessionChain?> GetChainAsync(SessionChainId chainId, CancellationToken ct = default);
1720
Task SaveChainAsync(UAuthSessionChain chain, long expectedVersion, CancellationToken ct = default);
@@ -20,6 +23,7 @@ public interface ISessionStore
2023
Task RevokeOtherChainsAsync(TenantKey tenant, UserKey user, SessionChainId keepChain, DateTimeOffset at, CancellationToken ct = default);
2124
Task RevokeAllChainsAsync(TenantKey tenant, UserKey user, DateTimeOffset at, CancellationToken ct = default);
2225
Task RevokeChainCascadeAsync(SessionChainId chainId, DateTimeOffset at, CancellationToken ct = default);
26+
Task LogoutChainAsync(SessionChainId chainId, DateTimeOffset at, CancellationToken ct = default);
2327

2428
Task<UAuthSessionRoot?> GetRootByUserAsync(UserKey userKey, CancellationToken ct = default);
2529
Task<UAuthSessionRoot?> GetRootByIdAsync(SessionRootId rootId, CancellationToken ct = default);
@@ -30,7 +34,7 @@ public interface ISessionStore
3034

3135
Task<SessionChainId?> GetChainIdBySessionAsync(AuthSessionId sessionId, CancellationToken ct = default);
3236
Task<IReadOnlyList<UAuthSessionChain>> GetChainsByUserAsync(UserKey userKey, bool includeHistoricalRoots = false, CancellationToken ct = default);
37+
Task<UAuthSessionChain?> GetChainByDeviceAsync(TenantKey tenant, UserKey userKey, DeviceId deviceId, CancellationToken ct = default);
3338
Task<IReadOnlyList<UAuthSessionChain>> GetChainsByRootAsync(SessionRootId rootId, CancellationToken ct = default);
3439
Task<IReadOnlyList<UAuthSession>> GetSessionsByChainAsync(SessionChainId chainId, CancellationToken ct = default);
35-
Task DeleteExpiredSessionsAsync(DateTimeOffset at, CancellationToken ct = default);
3640
}

src/CodeBeam.UltimateAuth.Core/Contracts/Login/LoginRequest.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,4 @@ public sealed record LoginRequest
1717
/// Server policy may still ignore this.
1818
/// </summary>
1919
public bool RequestTokens { get; init; } = true;
20-
21-
// Optional
22-
public SessionChainId? ChainId { get; init; }
2320
}

0 commit comments

Comments
 (0)