diff --git a/UltimateAuth.slnx b/UltimateAuth.slnx index 5f659632..751ea927 100644 --- a/UltimateAuth.slnx +++ b/UltimateAuth.slnx @@ -13,6 +13,7 @@ + diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/CodeBeam.UltimateAuth.Docs.Wasm.Client.csproj b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/CodeBeam.UltimateAuth.Docs.Wasm.Client.csproj index 3e3e1fb5..69a55d41 100644 --- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/CodeBeam.UltimateAuth.Docs.Wasm.Client.csproj +++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/CodeBeam.UltimateAuth.Docs.Wasm.Client.csproj @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/Samples.razor b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/Samples.razor index a1974cbd..dee6fad4 100644 --- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/Samples.razor +++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/Samples.razor @@ -5,7 +5,7 @@ Samples Explore working examples and see UltimateAuth in action. - Interactive online samples are coming soon. + Identity Lab (hosted live demo) is coming soon. @@ -15,6 +15,14 @@ + + + Sample.Shared + Shared component designs across all modern .NET platforms. + View Source Code on GitHub + + + Blazor Server (EF Core) @@ -31,9 +39,9 @@ - + - Blazor WASM (Standalone) + Blazor Standalone WASM Client-side sample using Hybrid authentication model. View Source Code on GitHub @@ -41,7 +49,23 @@ - UAuthHub + Blazor Interactive WASM + Client-side interactive render mode sample using Hybrid authentication model. + View Source Code on GitHub + + + + + + UAuthHub (EF Core) + Complete Auth server with UI, working together with WASM client and EF Core. + View Source Code on GitHub + + + + + + UAuthHub (InMemory) Complete Auth server with UI, working together with WASM client. View Source Code on GitHub @@ -54,20 +78,91 @@ View Source Code on GitHub - - - - WASM Sample Setup:
- Start the following projects together:
- (1) UAuthHub
- (2) ResourceApi
- (3) BlazorStandaloneWasm
- After opening the solution, configure multiple startup projects in Visual Studio. -
- - - Each sample refreshes (clear + seed) it's data on each restart. When you close application it will be reset. - + + + + + + + + + Running the Samples + + + + The samples are preconfigured with different hosting and storage setups. + Follow the project combinations below to run them locally. + + + + + + Blazor Server + Standalone + + + + Run either Blazor Server (InMemory) or Blazor Server (EF Core) independently. + No additional projects are required. + + + + + + + + Blazor Standalone WASM + 3 Projects + + + Start these projects together: + + + 1. UAuthHub + 2. ResourceApi + 3. BlazorStandaloneWasm + + + Preconfigured with InMemory storage. + + + + + + + Blazor Interactive WASM + 3 Projects + + + Start these projects together: + + + 1. UAuthHub EF Core + 2. Resource API EF Core + 3. Blazor Interactive WASM + + + Preconfigured with EF Core storage. + + + + + Storage flexibility: + These are sample configurations, not framework limitations. + Both WASM hosting models can use InMemory or EF Core backends. + The combinations above are simply the preconfigured examples provided in this repository. + + + + In Visual Studio, open Configure Startup Projects, select Multiple startup projects, and set the required projects to Start. + + + + Sample Data: + Sample data is reset and seeded again on each restart in the provided demo configurations. + + +
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.csproj b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.csproj index 300b60ef..be947b19 100644 --- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.csproj +++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.csproj @@ -10,7 +10,7 @@ - +
diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor similarity index 93% rename from samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor index 2806b7d3..b18f2338 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor @@ -1,4 +1,4 @@ -@namespace CodeBeam.UltimateAuth.Sample +@namespace CodeBeam.UltimateAuth.Sample.Shared @inherits ComponentBase diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor.cs similarity index 94% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor.cs index 030d9b66..9425b43c 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogo.razor.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; -namespace CodeBeam.UltimateAuth.Sample; +namespace CodeBeam.UltimateAuth.Sample.Shared; public partial class UAuthLogo : ComponentBase { diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogoVariant.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogoVariant.cs similarity index 51% rename from samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogoVariant.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogoVariant.cs index fe3be220..fc543d89 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogoVariant.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Brand/UAuthLogoVariant.cs @@ -1,4 +1,4 @@ -namespace CodeBeam.UltimateAuth.Sample; +namespace CodeBeam.UltimateAuth.Sample.Shared; public enum UAuthLogoVariant { diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/CodeBeam.UltimateAuth.Sample.Shared.csproj b/samples/CodeBeam.UltimateAuth.Sample.Shared/CodeBeam.UltimateAuth.Sample.Shared.csproj new file mode 100644 index 00000000..f1d71e85 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/CodeBeam.UltimateAuth.Sample.Shared.csproj @@ -0,0 +1,28 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Common/UAuthDialog.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Common/UAuthDialog.cs similarity index 92% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Common/UAuthDialog.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Common/UAuthDialog.cs index caa73d6b..8e16bbe6 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Common/UAuthDialog.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Common/UAuthDialog.cs @@ -2,7 +2,7 @@ using CodeBeam.UltimateAuth.Core.Domain; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Common; +namespace CodeBeam.UltimateAuth.Sample.Shared.Common; public static class UAuthDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Custom/UAuthPageComponent.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Custom/UAuthPageComponent.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Custom/UAuthPageComponent.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Custom/UAuthPageComponent.razor diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/AccountStatusDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/AccountStatusDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/AccountStatusDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/AccountStatusDialog.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/AccountStatusDialog.razor.cs similarity index 97% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/AccountStatusDialog.razor.cs index d5652e62..c7fc1d63 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/AccountStatusDialog.razor.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class AccountStatusDialog { diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor similarity index 90% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor index 9a514935..20127849 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor @@ -1,6 +1,4 @@ -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient +@inject IUAuthClient UAuthClient @inject ISnackbar Snackbar diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor.cs similarity index 95% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor.cs index d96ee282..56b88169 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CreateUserDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CreateUserDialog.razor.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class CreateUserDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CredentialDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CredentialDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CredentialDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CredentialDialog.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CredentialDialog.razor.cs similarity index 97% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CredentialDialog.razor.cs index fa3f8117..d860c4b4 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/CredentialDialog.razor.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class CredentialDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/IdentifierDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/IdentifierDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/IdentifierDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/IdentifierDialog.razor diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/IdentifierDialog.razor.cs similarity index 99% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/IdentifierDialog.razor.cs index 77d8e254..0612671d 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/IdentifierDialog.razor.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class IdentifierDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/PermissionDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/PermissionDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/PermissionDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/PermissionDialog.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/PermissionDialog.razor.cs similarity index 98% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/PermissionDialog.razor.cs index b6b03bb8..aeb9c1c9 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/PermissionDialog.razor.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class PermissionDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ProfileDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ProfileDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ProfileDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ProfileDialog.razor diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ProfileDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ProfileDialog.razor.cs similarity index 97% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ProfileDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ProfileDialog.razor.cs index 43b08720..673a3610 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ProfileDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ProfileDialog.razor.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class ProfileDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ResetDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResetDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ResetDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResetDialog.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResetDialog.razor.cs similarity index 94% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResetDialog.razor.cs index 349f56ff..96251caf 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResetDialog.razor.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class ResetDialog { diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor similarity index 96% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor index c235fb4b..448d9c1d 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor @@ -1,5 +1,5 @@ -@using CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi -@inject ProductApiService Api +@using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi +@inject SampleProductApiService Api @inject ISnackbar Snackbar diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor.cs similarity index 90% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor.cs index 7b6f3ebb..5c861ecc 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResourceApiDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/ResourceApiDialog.razor.cs @@ -1,12 +1,9 @@ using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi; -using CodeBeam.UltimateAuth.Users.Contracts; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class ResourceApiDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/RoleDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/RoleDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/RoleDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/RoleDialog.razor diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/RoleDialog.razor.cs similarity index 98% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/RoleDialog.razor.cs index 453acb8c..6447c7c4 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/RoleDialog.razor.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class RoleDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor similarity index 99% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor index 8ecf2a15..efba51c4 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor @@ -1,5 +1,4 @@ @using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts @inject IUAuthClient UAuthClient @inject ISnackbar Snackbar @inject IDialogService DialogService diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor.cs similarity index 99% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor.cs index 17af4337..2c5d3934 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/SessionDialog.razor.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class SessionDialog { diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor similarity index 96% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor index 39053d5e..97631deb 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor @@ -1,6 +1,4 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UAuth.Sample.IntWasm.Client.Common -@using CodeBeam.UltimateAuth.Users.Contracts +@using CodeBeam.UltimateAuth.Users.Contracts @inject IUAuthClient UAuthClient @inject IDialogService DialogService @inject ISnackbar Snackbar diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor.cs similarity index 95% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor.cs index 7228a3d2..9f4baa1a 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserDetailDialog.razor.cs @@ -1,12 +1,12 @@ using CodeBeam.UltimateAuth.Client; using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Common; +using CodeBeam.UltimateAuth.Sample.Shared.Common; using CodeBeam.UltimateAuth.Users.Contracts; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class UserDetailDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserRoleDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserRoleDialog.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserRoleDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserRoleDialog.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserRoleDialog.razor.cs similarity index 98% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserRoleDialog.razor.cs index b167d6db..47a2c4ae 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UserRoleDialog.razor.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class UserRoleDialog { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor similarity index 98% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor index bf19af4e..66c8e887 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor @@ -1,5 +1,4 @@ @using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorServer.Common @using CodeBeam.UltimateAuth.Users.Contracts @inject IUAuthClient UAuthClient @inject IDialogService DialogService diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor.cs similarity index 97% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor.cs index 5d184fe7..e945d65a 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UsersDialog.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Dialogs/UsersDialog.razor.cs @@ -1,12 +1,12 @@ using CodeBeam.UltimateAuth.Client; using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Common; +using CodeBeam.UltimateAuth.Sample.Shared.Common; using CodeBeam.UltimateAuth.Users.Contracts; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; public partial class UsersDialog { diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor new file mode 100644 index 00000000..fd0bbd96 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor @@ -0,0 +1,101 @@ +@inherits UAuthHubLayoutBase +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar +@inject NavigationManager Nav + +@if (!IsHubActive) +{ + + + UltimateAuth + + @Title + + + + + + + + + + + + Access Denied + + + This page cannot be accessed directly. + UAuthHub login flows can only be initiated by an authorized client application. + + + + + + UltimateAuth protects this resource based on your session and permissions. + + + + + return; +} + + + + + UltimateAuth + + UAuthHub Sample + + + + + + + + + +
+ + + @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") + + +
+
+ + + @state.Identity?.DisplayName + @string.Join(", ", state.Claims.Roles) + + + + + + + + @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) + { + + + } + +
+
+ + + + +
+
+ + + @ChildContent + +
+ + +
+ An unhandled error has occurred. + Reload + 🗙 +
diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor.cs similarity index 92% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor.cs index 92d16814..c59556ab 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleHubMainLayout.razor.cs @@ -3,13 +3,13 @@ using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Layout; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Layout; -public partial class MainLayout +public partial class SampleHubMainLayout { [CascadingParameter] public UAuthState UAuth { get; set; } = default!; @@ -17,6 +17,12 @@ public partial class MainLayout [CascadingParameter] public DarkModeManager DarkModeManager { get; set; } = default!; + [Parameter] + public RenderFragment ChildContent { get; set; } = default!; + + [Parameter] + public string? Title { get; set; } = "UAuthHub Sample"; + private async Task Refresh() { await UAuthClient.Flows.RefreshAsync(); diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor new file mode 100644 index 00000000..4d367b16 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor @@ -0,0 +1,57 @@ +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar +@inject NavigationManager Nav + + + + + UltimateAuth + + @Title + + + + + + + + + +
+ + + @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") + + +
+
+ + + @state.Identity?.DisplayName + @string.Join(", ", state.Claims.Roles) + + + + + + + + @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) + { + + + } + +
+
+ + + + +
+
+ + + @ChildContent + +
diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor.cs similarity index 92% rename from samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor.cs index 4b35a909..b98cb058 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Layout/SampleMainLayout.razor.cs @@ -3,13 +3,13 @@ using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.UAuthHub.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; using Microsoft.AspNetCore.Components; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Layout; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Layout; -public partial class MainLayout +public partial class SampleMainLayout { [CascadingParameter] public UAuthState UAuth { get; set; } = default!; @@ -17,6 +17,12 @@ public partial class MainLayout [CascadingParameter] public DarkModeManager DarkModeManager { get; set; } = default!; + [Parameter] + public RenderFragment ChildContent { get; set; } = default!; + + [Parameter] + public string? Title { get; set; } + private async Task Refresh() { await UAuthClient.Flows.RefreshAsync(); diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/NotAuthorized.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/NotAuthorized.razor similarity index 100% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/NotAuthorized.razor rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/NotAuthorized.razor diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/NotAuthorized.razor.cs similarity index 82% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/NotAuthorized.razor.cs index a59522db..eb018194 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/NotAuthorized.razor.cs @@ -1,4 +1,4 @@ -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; public partial class NotAuthorized { diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleAuthorizedTestPage.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleAuthorizedTestPage.razor new file mode 100644 index 00000000..20d3062f --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleAuthorizedTestPage.razor @@ -0,0 +1,30 @@ +@using CodeBeam.UltimateAuth.Core.Defaults +@inherits UAuthPageBase + + + + + + + Everything is Ok + + + If you see this section, it means you succesfully logged in. + + + + Go Home Page + + + + + + This is admin view content. + + + + UltimateAuth protects this resource based on your session and permissions. + + + + diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor new file mode 100644 index 00000000..ec51e981 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor @@ -0,0 +1,450 @@ +@inherits UAuthPageBase + +@inject IUAuthClient UAuthClient +@inject UAuthClientDiagnostics Diagnostics +@inject AuthenticationStateProvider AuthStateProvider +@inject ISnackbar Snackbar +@inject IDialogService DialogService +@using CodeBeam.UltimateAuth.Client.Diagnostics +@using CodeBeam.UltimateAuth.Core.Contracts +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Custom +@using Microsoft.AspNetCore.Components.Authorization + +@if (AuthState?.Identity?.UserStatus == UserStatus.SelfSuspended) +{ + + + + Your account is suspended. Please active it before continue. + + + + Set Active + Logout + + + + return; +} + +@if (AuthState?.Identity?.UserStatus == UserStatus.Suspended) +{ + + + + Your account is suspended. Please contact with administrator. + + + + Logout + + + + return; +} + + + + + + + + + + + Session + + + + + + + Validate + + + + + + Manual Refresh + + + + + + Logout + + + + + + Account + + + + + Manage Sessions + + + + Manage Profile + + + + Manage Identifiers + + + + Manage Credentials + + + + Suspend | Delete Account + + + + Admin + + + + + + + + + @if (_showAdminPreview) + { + + Admin operations are shown for preview. Sign in as an Admin to execute them. + + } + + @if (AuthState?.IsInRole("Admin") == true || _showAdminPreview) + { + + + + @* *@ + @* *@ + User Management + @* *@ + + + + + + @* *@ + Role Management + @* *@ + + + + } + + + Resource Api + + + + + Manage Resource + + + + + + + + + + + + @((AuthState?.Identity?.DisplayName ?? "?").Substring(0, Math.Min(2, (AuthState?.Identity?.DisplayName ?? "?").Length))) + + + + @AuthState?.Identity?.DisplayName + + @foreach (var role in AuthState?.Claims?.Roles ?? Enumerable.Empty()) + { + + @role + + } + + + + + + + + + + @if (_selectedAuthState == "UAuthState") + { + + +
+ + + Tenant + + @AuthState?.Identity?.Tenant.Value +
+ +
+ + +
+ + + User Id + + @AuthState?.Identity?.UserKey.Value +
+
+ + +
+ + + Authenticated + + @(AuthState?.IsAuthenticated == true ? "Yes" : "No") +
+
+ + +
+ + + Session State + + @AuthState?.Identity?.SessionState?.ToDescriptionString() +
+
+ + +
+ + + Username + + @AuthState?.Identity?.PrimaryUserName +
+
+ + +
+ + + Display Name + + @AuthState?.Identity?.DisplayName +
+
+ + + + + + + Email + + @AuthState?.Identity?.PrimaryEmail + + + + + + Phone + + @AuthState?.Identity?.PrimaryPhone + + + + + + + + Authenticated At + + @* TODO: Add IUAuthDateTimeFormatter *@ + @FormatLocalTime(AuthState?.Identity?.AuthenticatedAt) + + + + + + Last Validated At + + @* TODO: Validation call should update last validated at *@ + @FormatLocalTime(AuthState?.LastValidatedAt) + +
+ } + else if (_selectedAuthState == "AspNetCoreState") + { + + +
+ + + Authenticated + + @(_aspNetCoreState?.Identity?.IsAuthenticated == true ? "Yes" : "No") +
+
+ + +
+ + + User Id + + @_aspNetCoreState?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value +
+
+ + +
+ + + Username + + @_aspNetCoreState?.Identity?.Name +
+
+ + +
+ + + Authentication Type + + @_aspNetCoreState?.Identity?.AuthenticationType +
+
+
+ } +
+
+
+ + + + + + @GetHealthText() + + + Lifecycle + + + + + + Started + @Diagnostics.StartCount + + @if (Diagnostics.StartedAt is not null) + { + + + + @FormatRelative(Diagnostics.StartedAt) + + + } + + + + + Stopped + @Diagnostics.StopCount + + + + + + Terminated + @Diagnostics.TerminatedCount + + @if (Diagnostics.TerminatedAt is not null) + { + + + + + @FormatRelative(Diagnostics.TerminatedAt) + + + + } + + + + + + Refresh Metrics + + + + + + + Total Attempts + @Diagnostics.RefreshAttemptCount + + + + + + + Success + + @Diagnostics.RefreshSuccessCount + + + + + + Automatic + @Diagnostics.AutomaticRefreshCount + + + + + + Manual + @Diagnostics.ManualRefreshCount + + + + + + Touched/Rotated + @Diagnostics.RefreshTouchedCount / @Diagnostics.RefreshRotatedCount + + + + + + No-Op + @Diagnostics.RefreshNoOpCount + + + + + + Reauth Required + @Diagnostics.RefreshReauthRequiredCount + + + + + + + +
+
+
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor.cs similarity index 96% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor.cs index f14b1df3..f7ab64a6 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleHome.razor.cs @@ -3,16 +3,16 @@ using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UAuth.Sample.IntWasm.Client.Common; -using CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; using CodeBeam.UltimateAuth.Users.Contracts; using Microsoft.AspNetCore.Components.Authorization; using MudBlazor; using System.Security.Claims; +using CodeBeam.UltimateAuth.Sample.Shared.Common; +using CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class Home : UAuthPageBase +public partial class SampleHome : UAuthPageBase { private string _selectedAuthState = "UAuthState"; private ClaimsPrincipal? _aspNetCoreState; diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor new file mode 100644 index 00000000..29c446cd --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor @@ -0,0 +1,4 @@ +@using Microsoft.AspNetCore.Components.Authorization + +@inject NavigationManager Nav +@inject AuthenticationStateProvider AuthProvider diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor.cs similarity index 80% rename from samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor.cs index e5844e6d..7c20f85c 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLandingPage.razor.cs @@ -1,8 +1,8 @@ using CodeBeam.UltimateAuth.Core.Defaults; -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class LandingPage +public partial class SampleLandingPage { protected override async Task OnAfterRenderAsync(bool firstRender) { diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor new file mode 100644 index 00000000..34219171 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor @@ -0,0 +1,124 @@ +@inherits UAuthPageBase + +@implements IDisposable +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar +@inject IUAuthClientProductInfoProvider ClientProductInfoProvider +@inject IDeviceIdProvider DeviceIdProvider +@inject IDialogService DialogService + + + + + + + + + + + + + + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor.cs similarity index 96% rename from samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor.cs index 73d6ebd3..334cd26e 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleLogin.razor.cs @@ -2,12 +2,12 @@ using CodeBeam.UltimateAuth.Client.Runtime; using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; +using CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class Login : UAuthPageBase +public partial class SampleLogin : UAuthPageBase { private string? _username; private string? _password; diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor new file mode 100644 index 00000000..3850685d --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor @@ -0,0 +1,132 @@ +@inherits UAuthPageBase + +@implements IDisposable +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar +@inject IUAuthClientProductInfoProvider ClientProductInfoProvider +@inject IDeviceIdProvider DeviceIdProvider +@inject IDialogService DialogService + + + + + + + + + + + + + + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor.cs similarity index 95% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor.cs index 616df5f2..4e473d18 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SamplePkceLogin.razor.cs @@ -1,14 +1,13 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Blazor; +using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Runtime; using CodeBeam.UltimateAuth.Core.Contracts; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; +using CodeBeam.UltimateAuth.Sample.Shared.Components.Dialogs; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class Login : UAuthPageBase +public partial class SamplePkceLogin : UAuthPageBase { private string? _username; private string? _password; diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor new file mode 100644 index 00000000..98c53f24 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor @@ -0,0 +1,59 @@ +@inherits UAuthPageBase + +@implements IDisposable +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar +@inject IUAuthClientProductInfoProvider ClientProductInfoProvider +@inject IDeviceIdProvider DeviceIdProvider +@inject IDialogService DialogService + + + + + + + + + + + + + + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor.cs similarity index 91% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor.cs index a1917203..bf8814cf 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleRegister.razor.cs @@ -2,9 +2,9 @@ using CodeBeam.UltimateAuth.Users.Contracts; using MudBlazor; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class Register +public partial class SampleRegister { private string? _username; private string? _password; diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor new file mode 100644 index 00000000..38d911f5 --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor @@ -0,0 +1,17 @@ +@inherits UAuthPageBase + +@inject IUAuthClient UAuthClient +@inject ISnackbar Snackbar + + + + + + + + + Change Password + + + + \ No newline at end of file diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor.cs similarity index 94% rename from samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor.cs index 8a02dcf0..bfca22df 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/Page/SampleResetCredential.razor.cs @@ -1,9 +1,9 @@ using CodeBeam.UltimateAuth.Credentials.Contracts; using MudBlazor; -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; +namespace CodeBeam.UltimateAuth.Sample.Shared.Components.Page; -public partial class ResetCredential +public partial class SampleResetCredential { private MudForm _form = null!; private string? _code; diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/SampleRoutes.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/SampleRoutes.razor new file mode 100644 index 00000000..278fb57d --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Components/SampleRoutes.razor @@ -0,0 +1,81 @@ +@using System.Reflection +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Page +@using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure +@implements IDisposable + +@inject ISnackbar Snackbar +@inject DarkModeManager DarkModeManager + + + + + + + + + + + + @* Advanced: you can fully control routing by providing your own Router in UAuthApp component. *@ + @* + + + + + + + + + + + + + + + + *@ + + + + + + + + +@code { + [Parameter, EditorRequired] + public Assembly AppAssembly { get; set; } = default!; + + [Parameter, EditorRequired] + public Type DefaultLayout { get; set; } = default!; + + private Task HandleReauth() + { + Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); + return Task.CompletedTask; + } + + protected override void OnInitialized() + { + DarkModeManager.Changed += OnThemeChanged; + } + + private void OnThemeChanged() + { + _ = InvokeAsync(StateHasChanged); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await DarkModeManager.InitializeAsync(); + StateHasChanged(); + } + } + + public void Dispose() + { + DarkModeManager.Changed -= OnThemeChanged; + } +} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Infrastructure/DarkModeManager.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/Infrastructure/DarkModeManager.cs similarity index 93% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Infrastructure/DarkModeManager.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/Infrastructure/DarkModeManager.cs index 3f654e18..7b81d010 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Infrastructure/DarkModeManager.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/Infrastructure/DarkModeManager.cs @@ -1,7 +1,7 @@ using CodeBeam.UltimateAuth.Client.Contracts; using CodeBeam.UltimateAuth.Client.Infrastructure; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Infrastructure; +namespace CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; public sealed class DarkModeManager { diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/SampleProduct.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProduct.cs similarity index 61% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/SampleProduct.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProduct.cs index b169ecf3..c84ee0c7 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/SampleProduct.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProduct.cs @@ -1,4 +1,4 @@ -namespace CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi; +namespace CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; public class SampleProduct { diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/ProductApiService.cs b/samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProductApiService.cs similarity index 87% rename from samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/ProductApiService.cs rename to samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProductApiService.cs index 6220f56b..fb7c954f 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/ResourceApi/ProductApiService.cs +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/ResourceApi/SampleProductApiService.cs @@ -2,21 +2,24 @@ using Microsoft.AspNetCore.Components.WebAssembly.Http; using System.Net.Http.Json; -namespace CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi; +namespace CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; -public class ProductApiService +public class SampleProductApiService { private readonly HttpClient _http; - public ProductApiService(IHttpClientFactory factory) + public SampleProductApiService(HttpClient factory) { - _http = factory.CreateClient("resourceApi"); + _http = factory; } private HttpRequestMessage CreateRequest(HttpMethod method, string url, object? body = null) { var request = new HttpRequestMessage(method, url); - request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); + if (OperatingSystem.IsBrowser()) + { + request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); + } if (body is not null) { diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/_Imports.razor b/samples/CodeBeam.UltimateAuth.Sample.Shared/_Imports.razor new file mode 100644 index 00000000..7309978c --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/_Imports.razor @@ -0,0 +1,11 @@ +@using Microsoft.AspNetCore.Components.Web + +@using CodeBeam.UltimateAuth.Core.Abstractions +@using CodeBeam.UltimateAuth.Core.Domain +@using CodeBeam.UltimateAuth.Client +@using CodeBeam.UltimateAuth.Client.Runtime +@using CodeBeam.UltimateAuth.Client.Diagnostics +@using CodeBeam.UltimateAuth.Client.Blazor + +@using MudBlazor +@using MudExtensions diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/background.png b/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/background.png new file mode 100644 index 00000000..e15a3bde Binary files /dev/null and b/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/background.png differ diff --git a/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/sample.css b/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/sample.css new file mode 100644 index 00000000..3749f2be --- /dev/null +++ b/samples/CodeBeam.UltimateAuth.Sample.Shared/wwwroot/sample.css @@ -0,0 +1,91 @@ +.uauth-stack { + min-height: 60vh; + max-height: calc(100vh - var(--mud-appbar-height)); + width: 30vw; + min-width: 300px; +} + +.uauth-menu-popover { + width: 300px; +} + +.uauth-login-paper { + min-height: 70vh; +} + + .uauth-login-paper.mud-theme-primary { + background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); + color: white; + } + +.uauth-brand-glow { + filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); +} + +.uauth-logo-slide { + animation: uauth-logo-float 30s ease-in-out infinite; +} + +.uauth-text-transform-none .mud-button { + text-transform: none; +} + +.uauth-dialog { + height: 68vh; + max-height: 68vh; + overflow: auto; +} + +.text-secondary { + color: var(--mud-palette-text-secondary); +} + +.uauth-blur { + backdrop-filter: blur(10px); +} + +.uauth-blur-slight { + backdrop-filter: blur(4px); +} + +@keyframes uauth-logo-float { + 0% { + transform: translateY(0) rotateY(0); + } + + 10% { + transform: translateY(0) rotateY(0); + } + + 15% { + transform: translateY(200px) rotateY(360deg); + } + + 35% { + transform: translateY(200px) rotateY(360deg); + } + + 40% { + transform: translateY(200px) rotateY(720deg); + } + + 60% { + transform: translateY(200px) rotateY(720deg); + } + + 65% { + transform: translateY(0) rotateY(360deg); + } + + 85% { + transform: translateY(0) rotateY(360deg); + } + + 90% { + transform: translateY(0) rotateY(0); + } + + 100% { + transform: translateY(0) rotateY(0); + } +} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor.cs deleted file mode 100644 index 030d9b66..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogo.razor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace CodeBeam.UltimateAuth.Sample; - -public partial class UAuthLogo : ComponentBase -{ - [Parameter] public UAuthLogoVariant Variant { get; set; } = UAuthLogoVariant.Brand; - - [Parameter] public int Size { get; set; } = 32; - - [Parameter] public string? ShieldColor { get; set; } = "#00072d"; - [Parameter] public string? KeyColor { get; set; } = "#f6f5ae"; - - [Parameter] public string? Class { get; set; } - [Parameter] public string? Style { get; set; } - - private string BuildStyle() - { - if (Variant == UAuthLogoVariant.Mono) - return $"color: {KeyColor}; {Style}"; - - return Style ?? ""; - } - - protected string KeyPath => @" -M120.43,39.44H79.57A11.67,11.67,0,0,0,67.9,51.11V77.37 -A11.67,11.67,0,0,0,79.57,89H90.51l3.89,3.9v5.32l-3.8,3.81v81.41H99 -v-5.33h13.69V169H108.1v-3.8H99C99,150.76,111.9,153,111.9,153 -V99.79h-8V93.32L108.19,89h12.24 -A11.67,11.67,0,0,0,132.1,77.37V51.11 -A11.67,11.67,0,0,0,120.43,39.44Z - -M79.57,48.19h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.84a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.84a2.91,2.91 0 0 1 2.91,-2.92Z - -M79.57,68.62h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.83a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.83a2.91,2.91 0 0 1 2.91,-2.92Z - -M114.59,48.19h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.84a2.91,2.91 0 0 1 -2.91,2.91 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.91 -v-5.84a2.92,2.92 0 0 1 2.92,-2.92Z - -M114.59,68.62h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.83a2.91,2.91 0 0 1 -2.91,2.92 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.92 -v-5.83a2.92,2.92 0 0 1 2.92,-2.92Z -"; -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogoVariant.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogoVariant.cs deleted file mode 100644 index fe3be220..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Brand/UAuthLogoVariant.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample; - -public enum UAuthLogoVariant -{ - Brand, - Mono -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.csproj b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.csproj index 3bf1515b..a0aba4c9 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.csproj +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.csproj @@ -9,7 +9,6 @@ - all @@ -20,7 +19,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -29,6 +27,7 @@ +
diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/App.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/App.razor index 3156b071..39166419 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/App.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/App.razor @@ -9,6 +9,7 @@ + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor index 8eec2be6..cb4663ea 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor @@ -1,101 +1,5 @@ @inherits UAuthHubLayoutBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav -@if (!IsHubActive) -{ - - - UltimateAuth - - UAuthHub Sample - - - - - - - - - - - - Access Denied - - - This page cannot be accessed directly. - UAuthHub login flows can only be initiated by an authorized client application. - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - - return; -} - - - - - UltimateAuth - - UAuthHub Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
- - -
- An unhandled error has occurred. - Reload - 🗙 -
+ + @Body + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor.cs deleted file mode 100644 index 4b196823..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Infrastructure; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Components.Layout; - -public partial class MainLayout -{ - [CascadingParameter] - public UAuthState UAuth { get; set; } = default!; - - [CascadingParameter] - public DarkModeManager DarkModeManager { get; set; } = default!; - - private async Task Refresh() - { - await UAuthClient.Flows.RefreshAsync(); - } - - private async Task Logout() - { - await UAuthClient.Flows.LogoutAsync(); - } - - private Color GetBadgeColor() - { - if (UAuth is null || !UAuth.IsAuthenticated) - return Color.Error; - - if (UAuth.IsStale) - return Color.Warning; - - var state = UAuth.Identity?.SessionState; - - if (state is null || state == SessionState.Active) - return Color.Success; - - if (state == SessionState.Invalid) - return Color.Error; - - return Color.Warning; - } - - private void HandleSignInClick() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true); - return; - } - - GoToLoginWithReturn(); - } - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private void GoToLoginWithReturn() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login", replace: true); - return; - } - - var current = Nav.ToBaseRelativePath(uri.ToString()); - if (string.IsNullOrWhiteSpace(current)) - current = "home"; - - var returnUrl = Uri.EscapeDataString("/" + current.TrimStart('/')); - Nav.NavigateTo($"/login?returnUrl={returnUrl}", replace: true); - } -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/Home.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/Home.razor index b1720a39..dfd4c249 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/Home.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/Home.razor @@ -9,6 +9,7 @@ @using CodeBeam.UltimateAuth.Client.Runtime @using CodeBeam.UltimateAuth.Core.Abstractions @using CodeBeam.UltimateAuth.Core.Contracts +@using CodeBeam.UltimateAuth.Sample.Shared @using CodeBeam.UltimateAuth.Server.Services @using CodeBeam.UltimateAuth.Server.Stores @using Microsoft.Extensions.Options diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor deleted file mode 100644 index 2c0e9b77..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor +++ /dev/null @@ -1,27 +0,0 @@ -@inject NavigationManager Nav - - - - - - - Access Denied - - - You don’t have permission to view this page. - If you think this is a mistake, sign in with a different account or request access. - - - - Sign In - Go Back - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor.cs deleted file mode 100644 index 9d96c733..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Pages/NotAuthorized.razor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Components.Pages; - -public partial class NotAuthorized -{ - private string LoginHref - { - get - { - var returnUrl = Uri.EscapeDataString(Nav.ToBaseRelativePath(Nav.Uri)); - return $"/login?returnUrl=/{returnUrl}"; - } - } - - private void GoBack() => Nav.NavigateTo("/", replace: false); -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Routes.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Routes.razor index 9d7b5207..1b979547 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Routes.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Routes.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Components.Pages -@using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/_Imports.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/_Imports.razor index 56f13ea9..1629aac3 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/_Imports.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/_Imports.razor @@ -13,5 +13,8 @@ @using CodeBeam.UltimateAuth.Client @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Infrastructure/DarkModeManager.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Infrastructure/DarkModeManager.cs deleted file mode 100644 index 70ab1af0..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Infrastructure/DarkModeManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Contracts; -using CodeBeam.UltimateAuth.Client.Infrastructure; - -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Infrastructure; - -public sealed class DarkModeManager -{ - private const string StorageKey = "uauth:theme:dark"; - - private readonly IClientStorage _storage; - - public DarkModeManager(IClientStorage storage) - { - _storage = storage; - } - - public async Task InitializeAsync() - { - var value = await _storage.GetAsync(StorageScope.Local, StorageKey); - - if (bool.TryParse(value, out var parsed)) - IsDarkMode = parsed; - } - - public bool IsDarkMode { get; set; } - - public event Action? Changed; - - public async Task ToggleAsync() - { - IsDarkMode = !IsDarkMode; - - await _storage.SetAsync(StorageScope.Local, StorageKey, IsDarkMode.ToString()); - Changed?.Invoke(); - } - - public void Set(bool value) - { - if (IsDarkMode == value) - return; - - IsDarkMode = value; - Changed?.Invoke(); - } -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Program.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Program.cs index fe875991..13f1ebb3 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Program.cs +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Program.cs @@ -1,12 +1,11 @@ using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Infrastructure; using CodeBeam.UltimateAuth.EntityFrameworkCore; using CodeBeam.UltimateAuth.Sample.Seed.Extensions; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore; using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Components; -using CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore.Infrastructure; using CodeBeam.UltimateAuth.Server.Extensions; using Microsoft.EntityFrameworkCore; using MudBlazor.Services; diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-shm b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-shm index c4334748..7173a4eb 100644 Binary files a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-shm and b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-shm differ diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-wal b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-wal index 05e590d5..48e3f293 100644 Binary files a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-wal and b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/uauthhub.db-wal differ diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/wwwroot/app.css b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/wwwroot/app.css index 17fcfd6a..5588cc12 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/wwwroot/app.css +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/wwwroot/app.css @@ -49,100 +49,3 @@ h1:focus { .darker-border-checkbox.form-check-input { border-color: #929292; } - -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - - .uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; - } - - .uauth-login-paper.mud-theme-secondary { - background: linear-gradient(145deg, var(--mud-palette-secondary), rgba(0, 0, 0, 0.85) ); - color: white; - } - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor deleted file mode 100644 index 2806b7d3..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor +++ /dev/null @@ -1,19 +0,0 @@ -@namespace CodeBeam.UltimateAuth.Sample -@inherits ComponentBase - - - - @if (Variant == UAuthLogoVariant.Brand) - { - - - - } - else - { - - - - } - diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor.cs deleted file mode 100644 index 030d9b66..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Brand/UAuthLogo.razor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace CodeBeam.UltimateAuth.Sample; - -public partial class UAuthLogo : ComponentBase -{ - [Parameter] public UAuthLogoVariant Variant { get; set; } = UAuthLogoVariant.Brand; - - [Parameter] public int Size { get; set; } = 32; - - [Parameter] public string? ShieldColor { get; set; } = "#00072d"; - [Parameter] public string? KeyColor { get; set; } = "#f6f5ae"; - - [Parameter] public string? Class { get; set; } - [Parameter] public string? Style { get; set; } - - private string BuildStyle() - { - if (Variant == UAuthLogoVariant.Mono) - return $"color: {KeyColor}; {Style}"; - - return Style ?? ""; - } - - protected string KeyPath => @" -M120.43,39.44H79.57A11.67,11.67,0,0,0,67.9,51.11V77.37 -A11.67,11.67,0,0,0,79.57,89H90.51l3.89,3.9v5.32l-3.8,3.81v81.41H99 -v-5.33h13.69V169H108.1v-3.8H99C99,150.76,111.9,153,111.9,153 -V99.79h-8V93.32L108.19,89h12.24 -A11.67,11.67,0,0,0,132.1,77.37V51.11 -A11.67,11.67,0,0,0,120.43,39.44Z - -M79.57,48.19h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.84a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.84a2.91,2.91 0 0 1 2.91,-2.92Z - -M79.57,68.62h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.83a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.83a2.91,2.91 0 0 1 2.91,-2.92Z - -M114.59,48.19h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.84a2.91,2.91 0 0 1 -2.91,2.91 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.91 -v-5.84a2.92,2.92 0 0 1 2.92,-2.92Z - -M114.59,68.62h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.83a2.91,2.91 0 0 1 -2.91,2.92 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.92 -v-5.83a2.92,2.92 0 0 1 2.92,-2.92Z -"; -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.csproj b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.csproj index 5e9e2eee..361680e0 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.csproj +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.csproj @@ -9,9 +9,7 @@ - - @@ -21,6 +19,7 @@ +
diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/App.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/App.razor index 48e265d0..c5b1817e 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/App.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/App.razor @@ -9,7 +9,7 @@ - + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor index 8eec2be6..20691087 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor @@ -1,101 +1,5 @@ @inherits UAuthHubLayoutBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav -@if (!IsHubActive) -{ - - - UltimateAuth - - UAuthHub Sample - - - - - - - - - - - - Access Denied - - - This page cannot be accessed directly. - UAuthHub login flows can only be initiated by an authorized client application. - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - - return; -} - - - - - UltimateAuth - - UAuthHub Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
- - -
- An unhandled error has occurred. - Reload - 🗙 -
+ + @Body + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Home.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Home.razor index b1720a39..dfd4c249 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Home.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Home.razor @@ -9,6 +9,7 @@ @using CodeBeam.UltimateAuth.Client.Runtime @using CodeBeam.UltimateAuth.Core.Abstractions @using CodeBeam.UltimateAuth.Core.Contracts +@using CodeBeam.UltimateAuth.Sample.Shared @using CodeBeam.UltimateAuth.Server.Services @using CodeBeam.UltimateAuth.Server.Stores @using Microsoft.Extensions.Options diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor deleted file mode 100644 index 2c0e9b77..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor +++ /dev/null @@ -1,27 +0,0 @@ -@inject NavigationManager Nav - - - - - - - Access Denied - - - You don’t have permission to view this page. - If you think this is a mistake, sign in with a different account or request access. - - - - Sign In - Go Back - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor.cs deleted file mode 100644 index 4e750030..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/NotAuthorized.razor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Pages; - -public partial class NotAuthorized -{ - private string LoginHref - { - get - { - var returnUrl = Uri.EscapeDataString(Nav.ToBaseRelativePath(Nav.Uri)); - return $"/login?returnUrl=/{returnUrl}"; - } - } - - private void GoBack() => Nav.NavigateTo("/", replace: false); -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Routes.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Routes.razor index 22f83d10..1b979547 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Routes.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Routes.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Pages -@using CodeBeam.UltimateAuth.Sample.UAuthHub.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/_Imports.razor b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/_Imports.razor index f530884f..8b565a7f 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/_Imports.razor +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/_Imports.razor @@ -14,5 +14,8 @@ @using CodeBeam.UltimateAuth.Client @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Infrastructure/DarkModeManager.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Infrastructure/DarkModeManager.cs deleted file mode 100644 index 95b63347..00000000 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Infrastructure/DarkModeManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Contracts; -using CodeBeam.UltimateAuth.Client.Infrastructure; - -namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Infrastructure; - -public sealed class DarkModeManager -{ - private const string StorageKey = "uauth:theme:dark"; - - private readonly IClientStorage _storage; - - public DarkModeManager(IClientStorage storage) - { - _storage = storage; - } - - public async Task InitializeAsync() - { - var value = await _storage.GetAsync(StorageScope.Local, StorageKey); - - if (bool.TryParse(value, out var parsed)) - IsDarkMode = parsed; - } - - public bool IsDarkMode { get; set; } - - public event Action? Changed; - - public async Task ToggleAsync() - { - IsDarkMode = !IsDarkMode; - - await _storage.SetAsync(StorageScope.Local, StorageKey, IsDarkMode.ToString()); - Changed?.Invoke(); - } - - public void Set(bool value) - { - if (IsDarkMode == value) - return; - - IsDarkMode = value; - Changed?.Invoke(); - } -} diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Program.cs b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Program.cs index 814fd843..592d01b9 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Program.cs +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Program.cs @@ -1,11 +1,10 @@ using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Infrastructure; using CodeBeam.UltimateAuth.InMemory; using CodeBeam.UltimateAuth.Sample.Seed.Extensions; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; using CodeBeam.UltimateAuth.Sample.UAuthHub.Components; -using CodeBeam.UltimateAuth.Sample.UAuthHub.Infrastructure; using CodeBeam.UltimateAuth.Server.Extensions; using MudBlazor.Services; using MudExtensions.Services; diff --git a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/wwwroot/app.css b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/wwwroot/app.css index 17fcfd6a..5588cc12 100644 --- a/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/wwwroot/app.css +++ b/samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/wwwroot/app.css @@ -49,100 +49,3 @@ h1:focus { .darker-border-checkbox.form-check-input { border-color: #929292; } - -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - - .uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; - } - - .uauth-login-paper.mud-theme-secondary { - background: linear-gradient(145deg, var(--mud-palette-secondary), rgba(0, 0, 0, 0.85) ); - color: white; - } - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor deleted file mode 100644 index 2806b7d3..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogo.razor +++ /dev/null @@ -1,19 +0,0 @@ -@namespace CodeBeam.UltimateAuth.Sample -@inherits ComponentBase - - - - @if (Variant == UAuthLogoVariant.Brand) - { - - - - } - else - { - - - - } - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogoVariant.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogoVariant.cs deleted file mode 100644 index fe3be220..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Brand/UAuthLogoVariant.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample; - -public enum UAuthLogoVariant -{ - Brand, - Mono -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.csproj b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.csproj index 98b4e775..9f0beb00 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.csproj +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.csproj @@ -19,8 +19,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - @@ -28,6 +26,7 @@ +
diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Common/UAuthDialog.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Common/UAuthDialog.cs deleted file mode 100644 index 2183c80d..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Common/UAuthDialog.cs +++ /dev/null @@ -1,29 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common; - -public static class UAuthDialog -{ - public static DialogParameters GetDialogParameters(UAuthState state, UserKey? userKey = null) - { - DialogParameters parameters = new DialogParameters(); - parameters.Add("AuthState", state); - if (userKey != null ) - { - parameters.Add("UserKey", userKey); - } - return parameters; - } - - public static DialogOptions GetDialogOptions(MaxWidth maxWidth = MaxWidth.Medium) - { - return new DialogOptions - { - MaxWidth = maxWidth, - FullWidth = true, - CloseButton = true - }; - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/App.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/App.razor index 6acc099e..8a0d2a78 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/App.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/App.razor @@ -9,6 +9,7 @@ + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/AccountStatusDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/AccountStatusDialog.razor.cs deleted file mode 100644 index 195f1fbd..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/AccountStatusDialog.razor.cs +++ /dev/null @@ -1,77 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class AccountStatusDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task SuspendAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to suspend your account.

- You can still active your account later. - """, - yesText: "Suspend", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Suspend process cancelled.", Severity.Info); - return; - } - - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.SelfSuspended }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("Your account suspended successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } - - private async Task DeleteAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to delete your account.

- This action can't be undone.

- (Actually it is, admin can handle soft deleted accounts.) - """, - yesText: "Delete", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Deletion cancelled.", Severity.Info); - return; - } - - var result = await UAuthClient.Users.DeleteMeAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Your account deleted successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor deleted file mode 100644 index 9a514935..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor +++ /dev/null @@ -1,27 +0,0 @@ -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Create User - - - - - - - - - - - - - - - - Cancel - Create - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor.cs deleted file mode 100644 index a06a2acd..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CreateUserDialog.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class CreateUserDialog -{ - private MudForm _form = null!; - private string? _username; - private string? _email; - private string? _password; - private string? _passwordCheck; - private string? _displayName; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - private async Task CreateUserAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - if (_password != _passwordCheck) - { - Snackbar.Add("Passwords don't match.", Severity.Error); - return; - } - - var request = new CreateUserRequest - { - UserName = _username, - Email = _email, - DisplayName = _displayName, - Password = _password - }; - - var result = await UAuthClient.Users.CreateAsAdminAsync(request); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "User creation failed.", Severity.Error); - return; - } - - Snackbar.Add("User created successfully", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - - private string PasswordMatch(string? arg) => _password != arg ? "Passwords don't match." : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CredentialDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CredentialDialog.razor.cs deleted file mode 100644 index 13b4f69f..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/CredentialDialog.razor.cs +++ /dev/null @@ -1,92 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class CredentialDialog -{ - private MudForm _form = null!; - private string? _oldPassword; - private string? _newPassword; - private string? _newPasswordCheck; - private bool _passwordMode1 = false; - private bool _passwordMode2 = false; - private bool _passwordMode3 = true; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - private async Task ChangePasswordAsync() - { - if (_form is null) - return; - - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Form is not valid.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("New password and check do not match", Severity.Error); - return; - } - - ChangeCredentialRequest request; - - if (UserKey is null) - { - request = new ChangeCredentialRequest - { - CurrentSecret = _oldPassword!, - NewSecret = _newPassword! - }; - } - else - { - request = new ChangeCredentialRequest - { - NewSecret = _newPassword! - }; - } - - UAuthResult result; - if (UserKey is null) - { - result = await UAuthClient.Credentials.ChangeMyAsync(request); - } - else - { - result = await UAuthClient.Credentials.ChangeUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Password changed successfully", Severity.Success); - _oldPassword = null; - _newPassword = null; - _newPasswordCheck = null; - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "An error occurred while changing password", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/IdentifierDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/IdentifierDialog.razor.cs deleted file mode 100644 index 67a76cff..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/IdentifierDialog.razor.cs +++ /dev/null @@ -1,309 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class IdentifierDialog -{ - private MudDataGrid? _grid; - private UserIdentifierType _newIdentifierType; - private string? _newIdentifierValue; - private bool _newIdentifierPrimary; - private bool _loading = false; - private bool _reloadQueued; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - var result = await UAuthClient.Identifiers.GetMyAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - StateHasChanged(); - } - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Identifiers.GetMyAsync(req); - } - else - { - res = await UAuthClient.Identifiers.GetUserAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task CommittedItemChanges(UserIdentifierInfo item) - { - UpdateUserIdentifierRequest updateRequest = new() - { - Id = item.Id, - NewValue = item.Value - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UpdateMyAsync(updateRequest); - } - else - { - result = await UAuthClient.Identifiers.UpdateUserAsync(UserKey.Value, updateRequest); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier updated successfully.", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to update identifier.", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task AddNewIdentifier() - { - if (string.IsNullOrEmpty(_newIdentifierValue)) - { - Snackbar.Add("Value cannot be empty", Severity.Warning); - return; - } - - AddUserIdentifierRequest request = new() - { - Type = _newIdentifierType, - Value = _newIdentifierValue, - IsPrimary = _newIdentifierPrimary - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.AddMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.AddUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier added successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to add identifier.", Severity.Error); - } - } - - private async Task VerifyAsync(Guid id) - { - var demoInfo = await DialogService.ShowMessageBoxAsync( - title: "Demo Verification", - markupMessage: (MarkupString) - """ - This is a demo action.

- In a real app, you should verify identifiers via Email, SMS, or an Authenticator flow. - This will only mark the identifier as verified in UltimateAuth. - """, - yesText: "Verify", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (demoInfo != true) - { - Snackbar.Add("Verification cancelled", Severity.Info); - return; - } - - VerifyUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.VerifyMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.VerifyUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier verified successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to verify primary identifier.", Severity.Error); - } - } - - private async Task SetPrimaryAsync(Guid id) - { - SetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.SetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.SetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier set successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to set primary identifier.", Severity.Error); - } - } - - private async Task UnsetPrimaryAsync(Guid id) - { - UnsetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UnsetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.UnsetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier unset successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to unset primary identifier.", Severity.Error); - } - } - - private async Task DeleteIdentifier(Guid id) - { - DeleteUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.DeleteMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.DeleteUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier deleted successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to delete identifier.", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/PermissionDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/PermissionDialog.razor.cs deleted file mode 100644 index 0e755f76..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/PermissionDialog.razor.cs +++ /dev/null @@ -1,120 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class PermissionDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public RoleInfo Role { get; set; } = default!; - - private List _groups = new(); - - protected override void OnInitialized() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - _groups = catalog - .GroupBy(p => p.Split('.')[0]) - .Select(g => new PermissionGroup - { - Name = g.Key, - Items = g.Select(p => new PermissionItem - { - Value = p, - Selected = selected.Contains(p) - }).ToList() - }) - .OrderBy(x => x.Name) - .ToList(); - } - - private void ToggleGroup(PermissionGroup group, bool value) - { - foreach (var item in group.Items) - item.Selected = value; - } - - private void TogglePermission(PermissionItem item, bool value) - { - item.Selected = value; - } - - private bool? GetGroupState(PermissionGroup group) - { - var selected = group.Items.Count(x => x.Selected); - - if (selected == 0) - return false; - - if (selected == group.Items.Count) - return true; - - return null; - } - - private async Task Save() - { - var permissions = _groups.SelectMany(g => g.Items).Where(x => x.Selected).Select(x => Permission.From(x.Value)).ToList(); - - var req = new SetRolePermissionsRequest - { - RoleId = Role.Id, - Permissions = permissions - }; - - var result = await UAuthClient.Authorization.SetRolePermissionsAsync(req); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "Failed to update permissions", Severity.Error); - return; - } - - var result2 = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery() { Search = Role.Name }); - if (result2.Value?.Items is not null) - { - Role = result2.Value.Items.First(); - } - - Snackbar.Add("Permissions updated", Severity.Success); - RefreshUI(); - } - - private void RefreshUI() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - foreach (var group in _groups) - { - foreach (var item in group.Items) - { - item.Selected = selected.Contains(item.Value); - } - } - - StateHasChanged(); - } - - private void Cancel() => MudDialog.Cancel(); - - private class PermissionGroup - { - public string Name { get; set; } = ""; - public List Items { get; set; } = new(); - } - - private class PermissionItem - { - public string Value { get; set; } = ""; - public bool Selected { get; set; } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor deleted file mode 100644 index d09fcfa0..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor +++ /dev/null @@ -1,94 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - - - - - - Name - - - - - - - - - - - - - - - - - - - Personal - - - - - - - - - - - - - - - - - - - Localization - - - - - - - - - - - @foreach (var tz in TimeZoneInfo.GetSystemTimeZones()) - { - @tz.Id - @tz.DisplayName - } - - - - - - - - - - - - Cancel - Save - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor.cs deleted file mode 100644 index 0ce2be6f..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ProfileDialog.razor.cs +++ /dev/null @@ -1,114 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class ProfileDialog -{ - private MudForm? _form; - private string? _firstName; - private string? _lastName; - private string? _displayName; - private DateTime? _birthDate; - private string? _gender; - private string? _bio; - private string? _language; - private string? _timeZone; - private string? _culture; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.GetMeAsync(); - } - else - { - result = await UAuthClient.Users.GetUserAsync(UserKey.Value); - } - - if (result.IsSuccess && result.Value is not null) - { - var p = result.Value; - - _firstName = p.FirstName; - _lastName = p.LastName; - _displayName = p.DisplayName; - - _gender = p.Gender; - _birthDate = p.BirthDate?.ToDateTime(TimeOnly.MinValue); - _bio = p.Bio; - - _language = p.Language; - _timeZone = p.TimeZone; - _culture = p.Culture; - } - } - - private async Task SaveAsync() - { - if (AuthState is null || AuthState.Identity is null) - { - Snackbar.Add("No AuthState found.", Severity.Error); - return; - } - - if (_form is not null) - { - await _form.ValidateAsync(); - if (!_form.IsValid) - return; - } - - var request = new UpdateProfileRequest - { - FirstName = _firstName, - LastName = _lastName, - DisplayName = _displayName, - BirthDate = _birthDate.HasValue ? DateOnly.FromDateTime(_birthDate.Value) : null, - Gender = _gender, - Bio = _bio, - Language = _language, - TimeZone = _timeZone, - Culture = _culture - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.UpdateMyProfileAsync(request); - } - else - { - result = await UAuthClient.Users.UpdateUserProfileAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Profile updated", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to update profile", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor deleted file mode 100644 index 8d4c90d3..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor +++ /dev/null @@ -1,37 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Reset Credential - - - - - - This is a demonstration of how to implement a credential reset flow. - In a production application, you should use reset token or code in email, SMS etc. verification steps. - - - Reset request always returns ok even with not found users due to security reasons. - - - Request Reset - @if (_resetRequested) - { - Your reset code is on the server console. - Use Reset Code - } - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor.cs deleted file mode 100644 index 25c068f0..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/ResetDialog.razor.cs +++ /dev/null @@ -1,40 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class ResetDialog -{ - private bool _resetRequested = false; - private string? _identifier; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task RequestResetAsync() - { - var request = new BeginResetCredentialRequest - { - CredentialType = CredentialType.Password, - ResetCodeType = ResetCodeType.Code, - Identifier = _identifier ?? string.Empty - }; - - var result = await UAuthClient.Credentials.BeginResetAsync(request); - if (!result.IsSuccess || result.Value is null) - { - Snackbar.Add(result.ErrorText ?? "Failed to request credential reset.", Severity.Error); - return; - } - - _resetRequested = true; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/RoleDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/RoleDialog.razor.cs deleted file mode 100644 index 931687d8..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/RoleDialog.razor.cs +++ /dev/null @@ -1,164 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class RoleDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _newRoleName; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new RoleQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Authorization.QueryRolesAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task CommittedItemChanges(RoleInfo role) - { - var req = new RenameRoleRequest - { - Id = role.Id, - Name = role.Name - }; - - var result = await UAuthClient.Authorization.RenameRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add("Role renamed", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Rename failed", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task CreateRole() - { - if (string.IsNullOrWhiteSpace(_newRoleName)) - { - Snackbar.Add("Role name required.", Severity.Warning); - return; - } - - var req = new CreateRoleRequest - { - Name = _newRoleName - }; - - var res = await UAuthClient.Authorization.CreateRoleAsync(req); - - if (res.IsSuccess) - { - Snackbar.Add("Role created.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(res.ErrorText ?? "Creation failed.", Severity.Error); - } - } - - private async Task DeleteRole(RoleId roleId) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Delete role", - "Are you sure?", - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - return; - - var req = new DeleteRoleRequest() { Id = roleId }; - var result = await UAuthClient.Authorization.DeleteRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add($"Role deleted, assignments removed from {result.Value?.RemovedAssignments.ToString() ?? "unknown"} users.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Deletion failed.", Severity.Error); - } - } - - private async Task EditPermissions(RoleInfo role) - { - var dialog = await DialogService.ShowAsync( - "Edit Permissions", - new DialogParameters - { - { nameof(PermissionDialog.Role), role } - }, - new DialogOptions - { - CloseButton = true, - MaxWidth = MaxWidth.Large, - FullWidth = true - }); - - var result = await dialog.Result; - await ReloadAsync(); - } - - private async Task ReloadAsync() - { - _loading = true; - await Task.Delay(300); - if (_grid is null) - return; - - await _grid.ReloadServerData(); - _loading = false; - } - - private int GetPermissionCount(RoleInfo role) - { - var expanded = PermissionExpander.Expand(role.Permissions, UAuthPermissionCatalog.GetAdminPermissions()); - return expanded.Count; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor.cs deleted file mode 100644 index fb86d0cf..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/SessionDialog.razor.cs +++ /dev/null @@ -1,284 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class SessionDialog -{ - private MudDataGrid? _grid; - private bool _loading = false; - private bool _reloadQueued; - private SessionChainDetail? _chainDetail; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - var result = await UAuthClient.Sessions.GetMyChainsAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - StateHasChanged(); - } - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Sessions.GetMyChainsAsync(req); - } - else - { - res = await UAuthClient.Sessions.GetUserChainsAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task LogoutAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutAllMyDevicesAsync(); - } - else - { - result = await UAuthClient.Flows.LogoutAllUserDevicesAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task LogoutOthersAsync() - { - var result = await UAuthClient.Flows.LogoutMyOtherDevicesAsync(); - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of other devices.", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout", Severity.Error); - } - } - - private async Task LogoutDeviceAsync(SessionChainId chainId) - { - LogoutDeviceRequest request = new() { ChainId = chainId }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutMyDeviceAsync(request); - } - else - { - result = await UAuthClient.Flows.LogoutUserDeviceAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of device.", Severity.Success); - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeAllMyChainsAsync(); - } - else - { - result = await UAuthClient.Sessions.RevokeAllUserChainsAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeOthersAsync() - { - var result = await UAuthClient.Sessions.RevokeMyOtherChainsAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Revoked all other devices.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeChainAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeMyChainAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.RevokeUserChainAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - Snackbar.Add("Device revoked successfully.", Severity.Success); - - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task ShowChainDetailsAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.GetMyChainDetailAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.GetUserChainDetailAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - _chainDetail = result.Value; - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to fetch chain details.", Severity.Error); - _chainDetail = null; - } - } - - private void ClearDetail() - { - _chainDetail = null; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor deleted file mode 100644 index 73fafa48..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor +++ /dev/null @@ -1,75 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - @_user?.UserKey.Value - - - - - - - - Display Name - @_user?.DisplayName - - - - Username - @_user?.UserName - - - - Email - @_user?.PrimaryEmail - - - - Phone - @_user?.PrimaryPhone - - - - Created - @_user?.CreatedAt?.ToLocalTime() - - - - Status - @_user?.Status - - - @foreach (var s in Enum.GetValues()) - { - @s - } - - Change - - - - - - - - Management - - Sessions - Profile - Identifiers - Credentials - Roles - - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor.cs deleted file mode 100644 index 8a1a76a3..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserDetailDialog.razor.cs +++ /dev/null @@ -1,100 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class UserDetailDialog -{ - private UserView? _user; - private AdminAssignableUserStatus _status; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - var result = await UAuthClient.Users.GetUserAsync(UserKey); - - if (result.IsSuccess) - { - _user = result.Value; - _status = _user?.Status.ToAdminAssignableUserStatus() ?? AdminAssignableUserStatus.Unknown; - } - } - - private async Task OpenSessions() - { - await DialogService.ShowAsync("Session Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenProfile() - { - await DialogService.ShowAsync("Profile Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifiers() - { - await DialogService.ShowAsync("Identifier Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentials() - { - await DialogService.ShowAsync("Credentials", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenRoles() - { - await DialogService.ShowAsync("Roles", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task ChangeStatusAsync() - { - if (_user is null) - return; - - ChangeUserStatusAdminRequest request = new() - { - NewStatus = _status - }; - - var result = await UAuthClient.Users.ChangeUserStatusAsync(_user.UserKey, request); - - if (result.IsSuccess) - { - Snackbar.Add("User status updated", Severity.Success); - _user = _user with { Status = _status.ToUserStatus() }; - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private Color GetStatusColor(UserStatus? status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserRoleDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserRoleDialog.razor.cs deleted file mode 100644 index b1693a25..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UserRoleDialog.razor.cs +++ /dev/null @@ -1,124 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class UserRoleDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } = default!; - - private List _roles = new(); - private List _allRoles = new(); - - private string? _selectedRole; - - protected override async Task OnInitializedAsync() - { - await LoadRoles(); - } - - private async Task LoadRoles() - { - var userRoles = await UAuthClient.Authorization.GetUserRolesAsync(UserKey); - - if (userRoles.IsSuccess && userRoles.Value != null) - _roles = userRoles.Value.Roles.Items.Select(x => x.Name).ToList(); - - var roles = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery - { - PageNumber = 1, - PageSize = 200 - }); - - if (roles.IsSuccess && roles.Value != null) - _allRoles = roles.Value.Items.ToList(); - } - - private async Task AddRole() - { - if (string.IsNullOrWhiteSpace(_selectedRole)) - return; - - var request = new AssignRoleRequest - { - UserKey = UserKey, - RoleName = _selectedRole - }; - - var result = await UAuthClient.Authorization.AssignRoleToUserAsync(request); - - if (result.IsSuccess) - { - _roles.Add(_selectedRole); - Snackbar.Add("Role assigned", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - - _selectedRole = null; - } - - private async Task RemoveRole(string role) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Remove Role", - $"Remove {role} from user?", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - - if (role == "Admin") - { - var confirm2 = await DialogService.ShowMessageBoxAsync( - "Are You Sure", - "You are going to remove admin role. This action may cause the application unuseable.", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm2 != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - } - - var request = new RemoveRoleRequest - { - UserKey = UserKey, - RoleName = role - }; - - var result = await UAuthClient.Authorization.RemoveRoleFromUserAsync(request); - - if (result.IsSuccess) - { - _roles.Remove(role); - Snackbar.Add("Role removed.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private void Close() => MudDialog.Close(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor deleted file mode 100644 index 5fba5e4c..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor +++ /dev/null @@ -1,85 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - Browse, create and manage users - - - - - - - - - - - - - - - - - Users - - New User - - - - - - - - - - - @context.Item.Status - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.UserKey.Value - - - - Created At - @context.Item.CreatedAt - - - - - - - - - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor.cs deleted file mode 100644 index 3f963991..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Dialogs/UsersDialog.razor.cs +++ /dev/null @@ -1,176 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; - -public partial class UsersDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _search; - private bool _reloadQueued; - private UserStatus? _statusFilter; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task> LoadUsers(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new UserQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - Search = _search, - Status = _statusFilter, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Users.QueryAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed to load users.", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task OnStatusChanged(UserStatus? status) - { - _statusFilter = status; - await ReloadAsync(); - } - - private async Task OpenUser(UserKey userKey) - { - var dialog = await DialogService.ShowAsync("User", UAuthDialog.GetDialogParameters(AuthState, userKey), UAuthDialog.GetDialogOptions()); - await dialog.Result; - await ReloadAsync(); - } - - private async Task OpenCreateUser() - { - var dialog = await DialogService.ShowAsync( - "Create User", - new DialogOptions - { - MaxWidth = MaxWidth.Small, - FullWidth = true, - CloseButton = true - }); - - var result = await dialog.Result; - - if (result?.Canceled == false) - await ReloadAsync(); - } - - private async Task DeleteUserAsync(UserSummary user) - { - var confirm = await DialogService.ShowMessageBoxAsync( - title: "Delete user", - markupMessage: (MarkupString)$""" - Are you sure you want to delete {user.DisplayName ?? user.UserName ?? user.PrimaryEmail ?? user.UserKey}? -

- This operation is intended for admin usage. - """, - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions - { - MaxWidth = MaxWidth.Medium, - FullWidth = true, - BackgroundClass = "uauth-blur-slight" - }); - - if (confirm != true) - return; - - var req = new DeleteUserRequest - { - Mode = DeleteMode.Soft - }; - - var result = await UAuthClient.Users.DeleteUserAsync(user.UserKey, req); - - if (result.IsSuccess) - { - Snackbar.Add("User deleted successfully.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to delete user.", Severity.Error); - } - } - - private static Color GetStatusColor(UserStatus status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.SelfSuspended => Color.Warning, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor index 2e4a24bb..c78d7ae6 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor @@ -1,62 +1,8 @@ @inherits LayoutComponentBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav - - - - - UltimateAuth - - Blazor Server EFCore Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
+ + @Body +
An unhandled error has occurred. diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor.cs deleted file mode 100644 index 8ae19aa7..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Layout/MainLayout.razor.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Layout; - -public partial class MainLayout -{ - [CascadingParameter] - public UAuthState UAuth { get; set; } = default!; - - [CascadingParameter] - public DarkModeManager DarkModeManager { get; set; } = default!; - - private async Task Refresh() - { - await UAuthClient.Flows.RefreshAsync(); - } - - private async Task Logout() - { - await UAuthClient.Flows.LogoutAsync(); - } - - private Color GetBadgeColor() - { - if (UAuth is null || !UAuth.IsAuthenticated) - return Color.Error; - - if (UAuth.IsStale) - return Color.Warning; - - var state = UAuth.Identity?.SessionState; - - if (state is null || state == SessionState.Active) - return Color.Success; - - if (state == SessionState.Invalid) - return Color.Error; - - return Color.Warning; - } - - private void HandleSignInClick() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true); - return; - } - - GoToLoginWithReturn(); - } - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private void GoToLoginWithReturn() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login", replace: true); - return; - } - - var current = Nav.ToBaseRelativePath(uri.ToString()); - if (string.IsNullOrWhiteSpace(current)) - current = "home"; - - var returnUrl = Uri.EscapeDataString("/" + current.TrimStart('/')); - Nav.NavigateTo($"/login?returnUrl={returnUrl}", replace: true); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/AuthorizedTestPage.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/AuthorizedTestPage.razor index a5e4fde7..0a953043 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/AuthorizedTestPage.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/AuthorizedTestPage.razor @@ -1,27 +1,4 @@ @page "/authorized-test" @attribute [UAuthAuthorize] -@inherits UAuthPageBase - - - - - - Everything is Ok - - - If you see this section, it means you succesfully logged in. - - - - Go Profile - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor index 162c37ea..945a4332 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor @@ -1,444 +1,4 @@ @page "/home" @attribute [UAuthAuthorize] -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject UAuthClientDiagnostics Diagnostics -@inject AuthenticationStateProvider AuthStateProvider -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@using System.Security.Claims -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Custom -@using Microsoft.AspNetCore.Authorization - -@if (AuthState?.Identity?.UserStatus == UserStatus.SelfSuspended) -{ - - - - Your account is suspended. Please active it before continue. - - - - Set Active - Logout - - - - return; -} - -@if (AuthState?.Identity?.UserStatus == UserStatus.Suspended) -{ - - - - Your account is suspended. Please contact with administrator. - - - - Logout - - - - return; -} - - - - - - - - - - - Session - - - - - - - Validate - - - - - - Manual Refresh - - - - - - Logout - - - - - - Account - - - - - Manage Sessions - - - - Manage Profile - - - - Manage Identifiers - - - - Manage Credentials - - - - Suspend | Delete Account - - - - Admin - - - - - - - - - @if (_showAdminPreview) - { - - Admin operations are shown for preview. Sign in as an Admin to execute them. - - } - - @if (AuthState?.IsInRole("Admin") == true || _showAdminPreview) - { - - - - @* *@ - @* *@ - User Management - @* *@ - - - - - - @* *@ - Role Management - @* *@ - - - - } - - - - - - - - - - - @((AuthState?.Identity?.DisplayName ?? "?").Substring(0, Math.Min(2, (AuthState?.Identity?.DisplayName ?? "?").Length))) - - - - @AuthState?.Identity?.DisplayName - - @foreach (var role in AuthState?.Claims?.Roles ?? Enumerable.Empty()) - { - - @role - - } - - - - - - - - - - @if (_selectedAuthState == "UAuthState") - { - - -
- - - Tenant - - @AuthState?.Identity?.Tenant.Value -
- -
- - -
- - - User Id - - @AuthState?.Identity?.UserKey.Value -
-
- - -
- - - Authenticated - - @(AuthState?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - Session State - - @AuthState?.Identity?.SessionState?.ToDescriptionString() -
-
- - -
- - - Username - - @AuthState?.Identity?.PrimaryUserName -
-
- - -
- - - Display Name - - @AuthState?.Identity?.DisplayName -
-
- - - - - - - Email - - @AuthState?.Identity?.PrimaryEmail - - - - - - Phone - - @AuthState?.Identity?.PrimaryPhone - - - - - - - - Authenticated At - - @* TODO: Add IUAuthDateTimeFormatter *@ - @FormatLocalTime(AuthState?.Identity?.AuthenticatedAt) - - - - - - Last Validated At - - @* TODO: Validation call should update last validated at *@ - @FormatLocalTime(AuthState?.LastValidatedAt) - -
- } - else if (_selectedAuthState == "AspNetCoreState") - { - - -
- - - Authenticated - - @(_aspNetCoreState?.Identity?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - User Id - - @_aspNetCoreState?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value -
-
- - -
- - - Username - - @_aspNetCoreState?.Identity?.Name -
-
- - -
- - - Authentication Type - - @_aspNetCoreState?.Identity?.AuthenticationType -
-
-
- } -
-
-
- - - - - - @GetHealthText() - - - Lifecycle - - - - - - Started - @Diagnostics.StartCount - - @if (Diagnostics.StartedAt is not null) - { - - - - @FormatRelative(Diagnostics.StartedAt) - - - } - - - - - Stopped - @Diagnostics.StopCount - - - - - - Terminated - @Diagnostics.TerminatedCount - - @if (Diagnostics.TerminatedAt is not null) - { - - - - - @FormatRelative(Diagnostics.TerminatedAt) - - - - } - - - - - - Refresh Metrics - - - - - - - Total Attempts - @Diagnostics.RefreshAttemptCount - - - - - - - Success - - @Diagnostics.RefreshSuccessCount - - - - - - Automatic - @Diagnostics.AutomaticRefreshCount - - - - - - Manual - @Diagnostics.ManualRefreshCount - - - - - - Touched/Rotated - @Diagnostics.RefreshTouchedCount / @Diagnostics.RefreshRotatedCount - - - - - - No-Op - @Diagnostics.RefreshNoOpCount - - - - - - Reauth Required - @Diagnostics.RefreshReauthRequiredCount - - - - - - - -
-
-
+ \ No newline at end of file diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor.cs deleted file mode 100644 index 5764a674..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Home.razor.cs +++ /dev/null @@ -1,222 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Blazor; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Common; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components.Authorization; -using MudBlazor; -using System.Security.Claims; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class Home : UAuthPageBase -{ - private string _selectedAuthState = "UAuthState"; - private ClaimsPrincipal? _aspNetCoreState; - - private bool _showAdminPreview = false; - - protected override async Task OnInitializedAsync() - { - var initial = await AuthStateProvider.GetAuthenticationStateAsync(); - _aspNetCoreState = initial.User; - AuthStateProvider.AuthenticationStateChanged += OnAuthStateChanged; - Diagnostics.Changed += OnDiagnosticsChanged; - } - - private void OnAuthStateChanged(Task task) - { - _ = HandleAuthStateChangedAsync(task); - } - - private async Task HandleAuthStateChangedAsync(Task task) - { - try - { - var state = await task; - _aspNetCoreState = state.User; - await InvokeAsync(StateHasChanged); - } - catch - { - - } - } - - private void OnDiagnosticsChanged() - { - InvokeAsync(StateHasChanged); - } - - private async Task Logout() => await UAuthClient.Flows.LogoutAsync(); - - private async Task RefreshSession() => await UAuthClient.Flows.RefreshAsync(false); - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private Color GetHealthColor() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return Color.Warning; - - if (Diagnostics.TerminatedCount > 0) - return Color.Error; - - return Color.Success; - } - - private string GetHealthText() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return "Reauthentication Required"; - - if (Diagnostics.TerminatedCount > 0) - return "Session Terminated"; - - return "Healthy"; - } - - private string? FormatRelative(DateTimeOffset? utc) - { - if (utc is null) - return null; - - var diff = DateTimeOffset.UtcNow - utc.Value; - - if (diff.TotalSeconds < 5) - return "just now"; - - if (diff.TotalSeconds < 60) - return $"{(int)diff.Seconds} secs ago"; - - if (diff.TotalMinutes < 60) - return $"{(int)diff.TotalMinutes} min ago"; - - if (diff.TotalHours < 24) - return $"{(int)diff.TotalHours} hrs ago"; - - return utc.Value.ToLocalTime().ToString("dd MMM yyyy"); - } - - private string? FormatLocalTime(DateTimeOffset? utc) - { - return utc?.ToLocalTime().ToString("dd MMM yyyy • HH:mm:ss"); - } - - private async Task OpenProfileDialog() - { - await DialogService.ShowAsync("Manage Profile", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifierDialog() - { - await DialogService.ShowAsync("Manage Identifiers", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenSessionDialog() - { - await DialogService.ShowAsync("Manage Sessions", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentialDialog() - { - await DialogService.ShowAsync("Session Diagnostics", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenAccountStatusDialog() - { - await DialogService.ShowAsync("Manage Account", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.ExtraSmall)); - } - - private async Task OpenUserDialog() - { - await DialogService.ShowAsync("User Management", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.Large)); - } - - private async Task OpenRoleDialog() - { - await DialogService.ShowAsync("Role Management", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private DialogParameters GetDialogParameters() - { - return new DialogParameters - { - ["AuthState"] = AuthState - }; - } - - private async Task SetAccountActiveAsync() - { - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.Active }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Account activated successfully.", Severity.Success); - } - else - { - Snackbar.Add(result?.Problem?.Detail ?? result?.Problem?.Title ?? "Activation failed.", Severity.Error); - } - } - - public override void Dispose() - { - base.Dispose(); - AuthStateProvider.AuthenticationStateChanged -= OnAuthStateChanged; - Diagnostics.Changed -= OnDiagnosticsChanged; - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor index 1e4a9016..a02d91bf 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor @@ -1,4 +1,3 @@ @page "/" -@inject NavigationManager Nav -@inject AuthenticationStateProvider AuthProvider + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor.cs deleted file mode 100644 index 5733e2eb..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/LandingPage.razor.cs +++ /dev/null @@ -1,17 +0,0 @@ -using CodeBeam.UltimateAuth.Core.Defaults; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class LandingPage -{ - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (!firstRender) - return; - - var state = await AuthProvider.GetAuthenticationStateAsync(); - var isAuthenticated = state.User.Identity?.IsAuthenticated == true; - - Nav.NavigateTo(isAuthenticated ? "/home" : $"{UAuthConstants.Routes.LoginRedirect}?fresh=true"); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor index 5eec659a..65d20ded 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor @@ -1,126 +1,4 @@ @page "/login" @attribute [UAuthLoginPage] -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor.cs deleted file mode 100644 index 2c130d17..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Login.razor.cs +++ /dev/null @@ -1,211 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Blazor; -using CodeBeam.UltimateAuth.Client.Runtime; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Dialogs; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class Login : UAuthPageBase -{ - private string? _username; - private string? _password; - private UAuthClientProductInfo? _productInfo; - private MudTextField _usernameField = default!; - - private CancellationTokenSource? _lockoutCts; - private PeriodicTimer? _lockoutTimer; - private DateTimeOffset? _lockoutUntil; - private TimeSpan _remaining; - private bool _isLocked; - private DateTimeOffset? _lockoutStartedAt; - private TimeSpan _lockoutDuration; - private double _progressPercent; - private int? _remainingAttempts = null; - - protected override async Task OnInitializedAsync() - { - _productInfo = ClientProductInfoProvider.Get(); - } - - protected override Task OnUAuthPayloadAsync(AuthFlowPayload payload) - { - HandleLoginPayload(payload); - return Task.CompletedTask; - } - - protected override async Task OnFocusRequestedAsync() - { - await _usernameField.FocusAsync(); - } - - private void HandleLoginPayload(AuthFlowPayload payload) - { - if (payload.Flow != AuthFlowType.Login) - return; - - if (payload.Reason == AuthFailureReason.LockedOut && payload.LockoutUntilUtc is { } until) - { - _lockoutUntil = until; - StartCountdown(); - } - - _remainingAttempts = payload.RemainingAttempts; - ShowLoginError(payload.Reason, payload.RemainingAttempts); - } - - private void ShowLoginError(AuthFailureReason? reason, int? remainingAttempts) - { - string message = reason switch - { - AuthFailureReason.InvalidCredentials when remainingAttempts is > 0 - => $"Invalid username or password. {remainingAttempts} attempt(s) remaining.", - - AuthFailureReason.InvalidCredentials - => "Invalid username or password.", - - AuthFailureReason.RequiresMfa - => "Multi-factor authentication required.", - - AuthFailureReason.LockedOut - => "Your account is locked.", - - _ => "Login failed." - }; - - Snackbar.Add(message, Severity.Error); - } - - private async Task ProgrammaticLogin() - { - var request = new LoginRequest - { - Identifier = "admin", - Secret = "admin", - }; - await UAuthClient.Flows.LoginAsync(request, ReturnUrl ?? "/home"); - } - - private async void StartCountdown() - { - if (_lockoutUntil is null) - return; - - _isLocked = true; - _lockoutStartedAt = DateTimeOffset.UtcNow; - _lockoutDuration = _lockoutUntil.Value - DateTimeOffset.UtcNow; - UpdateRemaining(); - - _lockoutCts?.Cancel(); - _lockoutCts = new CancellationTokenSource(); - - _lockoutTimer?.Dispose(); - _lockoutTimer = new PeriodicTimer(TimeSpan.FromSeconds(1)); - - try - { - while (await _lockoutTimer.WaitForNextTickAsync(_lockoutCts.Token)) - { - UpdateRemaining(); - - if (_remaining <= TimeSpan.Zero) - { - ResetLockoutState(); - await InvokeAsync(StateHasChanged); - break; - } - - await InvokeAsync(StateHasChanged); - } - } - catch (OperationCanceledException) - { - - } - } - - private void ResetLockoutState() - { - _isLocked = false; - _lockoutUntil = null; - _progressPercent = 0; - _remainingAttempts = null; - } - - private void UpdateRemaining() - { - if (_lockoutUntil is null || _lockoutStartedAt is null) - return; - - var now = DateTimeOffset.UtcNow; - - _remaining = _lockoutUntil.Value - now; - - if (_remaining <= TimeSpan.Zero) - { - _remaining = TimeSpan.Zero; - return; - } - - var elapsed = now - _lockoutStartedAt.Value; - - if (_lockoutDuration.TotalSeconds > 0) - { - var percent = 100 - (elapsed.TotalSeconds / _lockoutDuration.TotalSeconds * 100); - _progressPercent = Math.Max(0, percent); - } - } - - private void HandleTry(IUAuthTryResult result) - { - if (result is TryLoginResult pkce) - { - if (!result.IsSuccess) - { - if (result.Reason == AuthFailureReason.LockedOut && result.LockoutUntilUtc is { } until) - { - _lockoutUntil = until; - StartCountdown(); - } - - _remainingAttempts = result.RemainingAttempts; - ShowLoginError(result.Reason, result.RemainingAttempts); - } - } - else - { - Snackbar.Add("Unexpected result type.", Severity.Error); - } - } - - private async Task OpenResetDialog() - { - await DialogService.ShowAsync("Reset Credentials", GetDialogParameters(), GetDialogOptions()); - } - - private DialogOptions GetDialogOptions() - { - return new DialogOptions - { - MaxWidth = MaxWidth.Medium, - FullWidth = true, - CloseButton = true - }; - } - - private DialogParameters GetDialogParameters() - { - return new DialogParameters - { - ["AuthState"] = AuthState - }; - } - - public override void Dispose() - { - base.Dispose(); - _lockoutCts?.Cancel(); - _lockoutTimer?.Dispose(); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/NotAuthorized.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/NotAuthorized.razor.cs deleted file mode 100644 index b38fbe97..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/NotAuthorized.razor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class NotAuthorized -{ - private string LoginHref - { - get - { - var returnUrl = Uri.EscapeDataString(Nav.ToBaseRelativePath(Nav.Uri)); - return $"/login?returnUrl=/{returnUrl}"; - } - } - - private void GoBack() => Nav.NavigateTo("/", replace: false); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor index 20b38b75..745143b0 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor @@ -1,60 +1,3 @@ @page "/register" -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor.cs deleted file mode 100644 index 41eadd64..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/Register.razor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Runtime; -using CodeBeam.UltimateAuth.Users.Contracts; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class Register -{ - private string? _username; - private string? _password; - private string? _passwordCheck; - private string? _email; - private UAuthClientProductInfo? _productInfo; - private MudForm _form = null!; - - protected override async Task OnInitializedAsync() - { - _productInfo = ClientProductInfoProvider.Get(); - } - - private async Task HandleRegisterAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - var request = new CreateUserRequest - { - UserName = _username, - Password = _password, - Email = _email, - }; - - var result = await UAuthClient.Users.CreateAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("User created successfully.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to create user.", Severity.Error); - } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor index 2623395b..f2c1a536 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor @@ -1,18 +1,3 @@ @page "/reset" -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - - - - - - Change Password - - - - \ No newline at end of file + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor.cs deleted file mode 100644 index 1569f1f4..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Pages/ResetCredential.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Credentials.Contracts; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages; - -public partial class ResetCredential -{ - private MudForm _form = null!; - private string? _code; - private string? _newPassword; - private string? _newPasswordCheck; - - private async Task ResetPasswordAsync() - { - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Please fix the validation errors.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("Passwords do not match.", Severity.Error); - return; - } - - if (string.IsNullOrEmpty(_code) || string.IsNullOrEmpty(_newPassword) || string.IsNullOrEmpty(Identifier)) - { - Snackbar.Add("Missing required information. Please ensure you have a valid reset code and new password.", Severity.Error); - return; - } - - var request = new CompleteResetCredentialRequest - { - ResetToken = _code, - NewSecret = _newPassword, - Identifier = Identifier // Coming from UAuthFlowPageBase automatically if begin reset is successful - }; - - var result = await UAuthClient.Credentials.CompleteResetAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Credential reset successfully. Please log in with your new password.", Severity.Success); - Navigation.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.Problem?.Detail ?? result.Problem?.Title ?? "Failed to reset credential. Please try again.", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Routes.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Routes.razor index 60331591..1b979547 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Routes.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/Routes.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components.Pages -@using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router (in the commented code below) *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/_Imports.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/_Imports.razor index 59225b8c..22b7f9e4 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/_Imports.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Components/_Imports.razor @@ -19,5 +19,9 @@ @using CodeBeam.UltimateAuth.Client.Diagnostics @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Page +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DarkModeManager.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DarkModeManager.cs deleted file mode 100644 index befbcb29..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DarkModeManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Contracts; -using CodeBeam.UltimateAuth.Client.Infrastructure; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure; - -public sealed class DarkModeManager -{ - private const string StorageKey = "uauth:theme:dark"; - - private readonly IClientStorage _storage; - - public DarkModeManager(IClientStorage storage) - { - _storage = storage; - } - - public async Task InitializeAsync() - { - var value = await _storage.GetAsync(StorageScope.Local, StorageKey); - - if (bool.TryParse(value, out var parsed)) - IsDarkMode = parsed; - } - - public bool IsDarkMode { get; set; } - - public event Action? Changed; - - public async Task ToggleAsync() - { - IsDarkMode = !IsDarkMode; - - await _storage.SetAsync(StorageScope.Local, StorageKey, IsDarkMode.ToString()); - Changed?.Invoke(); - } - - public void Set(bool value) - { - if (IsDarkMode == value) - return; - - IsDarkMode = value; - Changed?.Invoke(); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentBypassUserIdentifierVerifier.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentBypassUserIdentifierVerifier.cs new file mode 100644 index 00000000..b7992299 --- /dev/null +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentBypassUserIdentifierVerifier.cs @@ -0,0 +1,23 @@ +using CodeBeam.UltimateAuth.Users; +using Microsoft.Extensions.Hosting; + +namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure; + +// TODO: Replace this demo bypass with a real verification challenge flow. +// Never register this implementation in production. +internal sealed class DevelopmentBypassUserIdentifierVerifier(IHostEnvironment environment) : IUserIdentifierVerifier +{ + public const string DemoProof = "demo-verification-bypass"; + + public Task VerifyAsync(UserIdentifierVerificationContext context, CancellationToken ct = default) + { + ct.ThrowIfCancellationRequested(); + + if (!environment.IsDevelopment()) + { + throw new InvalidOperationException("Development verification bypass cannot run outside Development."); + } + + return Task.FromResult(string.Equals(context.Proof, DemoProof, StringComparison.Ordinal)); + } +} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentCredentialResetNotifier.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentCredentialResetNotifier.cs new file mode 100644 index 00000000..6acf68b2 --- /dev/null +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Infrastructure/DevelopmentCredentialResetNotifier.cs @@ -0,0 +1,21 @@ +using CodeBeam.UltimateAuth.Credentials; + +namespace CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure; + +internal sealed class DevelopmentCredentialResetNotifier(ILogger logger) : ICredentialResetNotifier +{ + public Task NotifyAsync(CredentialResetNotification notification, CancellationToken ct = default) + { + ct.ThrowIfCancellationRequested(); + + logger.LogWarning( + "DEVELOPMENT ONLY — Credential reset for tenant {Tenant}, " + + "user {UserKey}. Code: {Code}. Expires at: {ExpiresAt}", + notification.Tenant, + notification.UserKey, + notification.Token, + notification.ExpiresAt); + + return Task.CompletedTask; + } +} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Program.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Program.cs index 33b5d2af..0be8bbef 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Program.cs +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/Program.cs @@ -1,12 +1,12 @@ using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Infrastructure; using CodeBeam.UltimateAuth.EntityFrameworkCore; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components; -using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Infrastructure; using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore; +using CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore.Components; using CodeBeam.UltimateAuth.Sample.Seed.Extensions; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using CodeBeam.UltimateAuth.Server.Extensions; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.EntityFrameworkCore; @@ -66,6 +66,7 @@ }); builder.Services.AddScopedUltimateAuthSampleSeed(); +builder.Services.AddScoped(); builder.Services.Configure(options => { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-shm b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-shm index 7ce3780f..1623f1a4 100644 Binary files a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-shm and b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-shm differ diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-wal b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-wal index 6e7926c1..f62ad725 100644 Binary files a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-wal and b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/uauth.db-wal differ diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/wwwroot/app.css b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/wwwroot/app.css index 2b9a4745..2bd9b789 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/wwwroot/app.css +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer.EFCore/wwwroot/app.css @@ -49,95 +49,3 @@ h1:focus { .darker-border-checkbox.form-check-input { border-color: #929292; } - -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - -.uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; -} - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor deleted file mode 100644 index 2806b7d3..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor +++ /dev/null @@ -1,19 +0,0 @@ -@namespace CodeBeam.UltimateAuth.Sample -@inherits ComponentBase - - - - @if (Variant == UAuthLogoVariant.Brand) - { - - - - } - else - { - - - - } - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor.cs deleted file mode 100644 index 030d9b66..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogo.razor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace CodeBeam.UltimateAuth.Sample; - -public partial class UAuthLogo : ComponentBase -{ - [Parameter] public UAuthLogoVariant Variant { get; set; } = UAuthLogoVariant.Brand; - - [Parameter] public int Size { get; set; } = 32; - - [Parameter] public string? ShieldColor { get; set; } = "#00072d"; - [Parameter] public string? KeyColor { get; set; } = "#f6f5ae"; - - [Parameter] public string? Class { get; set; } - [Parameter] public string? Style { get; set; } - - private string BuildStyle() - { - if (Variant == UAuthLogoVariant.Mono) - return $"color: {KeyColor}; {Style}"; - - return Style ?? ""; - } - - protected string KeyPath => @" -M120.43,39.44H79.57A11.67,11.67,0,0,0,67.9,51.11V77.37 -A11.67,11.67,0,0,0,79.57,89H90.51l3.89,3.9v5.32l-3.8,3.81v81.41H99 -v-5.33h13.69V169H108.1v-3.8H99C99,150.76,111.9,153,111.9,153 -V99.79h-8V93.32L108.19,89h12.24 -A11.67,11.67,0,0,0,132.1,77.37V51.11 -A11.67,11.67,0,0,0,120.43,39.44Z - -M79.57,48.19h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.84a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.84a2.91,2.91 0 0 1 2.91,-2.92Z - -M79.57,68.62h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.83a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.83a2.91,2.91 0 0 1 2.91,-2.92Z - -M114.59,48.19h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.84a2.91,2.91 0 0 1 -2.91,2.91 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.91 -v-5.84a2.92,2.92 0 0 1 2.92,-2.92Z - -M114.59,68.62h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.83a2.91,2.91 0 0 1 -2.91,2.92 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.92 -v-5.83a2.92,2.92 0 0 1 2.92,-2.92Z -"; -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogoVariant.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogoVariant.cs deleted file mode 100644 index fe3be220..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Brand/UAuthLogoVariant.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample; - -public enum UAuthLogoVariant -{ - Brand, - Mono -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/CodeBeam.UltimateAuth.Sample.BlazorServer.csproj b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/CodeBeam.UltimateAuth.Sample.BlazorServer.csproj index 5345f4b9..cfe21912 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/CodeBeam.UltimateAuth.Sample.BlazorServer.csproj +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/CodeBeam.UltimateAuth.Sample.BlazorServer.csproj @@ -9,8 +9,6 @@ - - @@ -18,6 +16,7 @@ + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Common/UAuthDialog.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Common/UAuthDialog.cs deleted file mode 100644 index 58dae70b..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Common/UAuthDialog.cs +++ /dev/null @@ -1,29 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Common; - -public static class UAuthDialog -{ - public static DialogParameters GetDialogParameters(UAuthState state, UserKey? userKey = null) - { - DialogParameters parameters = new DialogParameters(); - parameters.Add("AuthState", state); - if (userKey != null ) - { - parameters.Add("UserKey", userKey); - } - return parameters; - } - - public static DialogOptions GetDialogOptions(MaxWidth maxWidth = MaxWidth.Medium) - { - return new DialogOptions - { - MaxWidth = maxWidth, - FullWidth = true, - CloseButton = true - }; - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/App.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/App.razor index 087e4279..1dd1096b 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/App.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/App.razor @@ -7,7 +7,7 @@ - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Custom/UAuthPageComponent.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Custom/UAuthPageComponent.razor deleted file mode 100644 index 5af543e4..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Custom/UAuthPageComponent.razor +++ /dev/null @@ -1,10 +0,0 @@ - - - @ChildContent - - - -@code { - [Parameter] - public RenderFragment? ChildContent { get; set; } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor deleted file mode 100644 index 0c91e45c..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor +++ /dev/null @@ -1,23 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - User: @AuthState?.Identity?.DisplayName - - - - - Suspend Account - - - - Delete Account - - - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor.cs deleted file mode 100644 index 4fda31ea..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/AccountStatusDialog.razor.cs +++ /dev/null @@ -1,77 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class AccountStatusDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task SuspendAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to suspend your account.

- You can still active your account later. - """, - yesText: "Suspend", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Suspend process cancelled.", Severity.Info); - return; - } - - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.SelfSuspended }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("Your account suspended successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } - - private async Task DeleteAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to delete your account.

- This action can't be undone.

- (Actually it is, admin can handle soft deleted accounts.) - """, - yesText: "Delete", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Deletion cancelled.", Severity.Info); - return; - } - - var result = await UAuthClient.Users.DeleteMeAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Your account deleted successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor deleted file mode 100644 index 9a514935..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor +++ /dev/null @@ -1,27 +0,0 @@ -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Create User - - - - - - - - - - - - - - - - Cancel - Create - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor.cs deleted file mode 100644 index af13ee27..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CreateUserDialog.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class CreateUserDialog -{ - private MudForm _form = null!; - private string? _username; - private string? _email; - private string? _password; - private string? _passwordCheck; - private string? _displayName; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - private async Task CreateUserAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - if (_password != _passwordCheck) - { - Snackbar.Add("Passwords don't match.", Severity.Error); - return; - } - - var request = new CreateUserRequest - { - UserName = _username, - Email = _email, - DisplayName = _displayName, - Password = _password - }; - - var result = await UAuthClient.Users.CreateAsAdminAsync(request); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "User creation failed.", Severity.Error); - return; - } - - Snackbar.Add("User created successfully", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - - private string PasswordMatch(string? arg) => _password != arg ? "Passwords don't match." : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor deleted file mode 100644 index 660b7c3a..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor +++ /dev/null @@ -1,51 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Credential Management - User: @AuthState?.Identity?.DisplayName - - - - - @if (UserKey == null) - { - - - - } - else - { - - - Administrators can directly assign passwords to users. - However, using the credential reset flow is generally recommended for better security and auditability. - - - } - - - - - - - - - - - @(UserKey is null ? "Change Password" : "Set Password") - - - - - - Cancel - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor.cs deleted file mode 100644 index 04ba3a44..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/CredentialDialog.razor.cs +++ /dev/null @@ -1,92 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class CredentialDialog -{ - private MudForm _form = null!; - private string? _oldPassword; - private string? _newPassword; - private string? _newPasswordCheck; - private bool _passwordMode1 = false; - private bool _passwordMode2 = false; - private bool _passwordMode3 = true; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - private async Task ChangePasswordAsync() - { - if (_form is null) - return; - - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Form is not valid.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("New password and check do not match", Severity.Error); - return; - } - - ChangeCredentialRequest request; - - if (UserKey is null) - { - request = new ChangeCredentialRequest - { - CurrentSecret = _oldPassword!, - NewSecret = _newPassword! - }; - } - else - { - request = new ChangeCredentialRequest - { - NewSecret = _newPassword! - }; - } - - UAuthResult result; - if (UserKey is null) - { - result = await UAuthClient.Credentials.ChangeMyAsync(request); - } - else - { - result = await UAuthClient.Credentials.ChangeUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Password changed successfully", Severity.Success); - _oldPassword = null; - _newPassword = null; - _newPasswordCheck = null; - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "An error occurred while changing password", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor deleted file mode 100644 index 0d631533..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/IdentifierDialog.razor +++ /dev/null @@ -1,106 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - - - - Identifiers - - - - - - - - - - - - - - - - - - - - - - - - - @if (context.Item.IsPrimary) - { - - - - } - else - { - - - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add - - - - - - - - Cancel - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor deleted file mode 100644 index 8e0df863..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor +++ /dev/null @@ -1,46 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using System.Reflection - -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Role Permissions - @Role.Name - - - - @* For Debug *@ - @* Current Permissions: @string.Join(", ", Role.Permissions) *@ - - @foreach (var group in _groups) - { - - - - - @group.Name (@group.Items.Count(x => x.Selected)/@group.Items.Count) - - - - - @foreach (var perm in group.Items) - { - - - - } - - - - } - - - - - Cancel - Save - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor.cs deleted file mode 100644 index 3f085402..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/PermissionDialog.razor.cs +++ /dev/null @@ -1,120 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class PermissionDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public RoleInfo Role { get; set; } = default!; - - private List _groups = new(); - - protected override void OnInitialized() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - _groups = catalog - .GroupBy(p => p.Split('.')[0]) - .Select(g => new PermissionGroup - { - Name = g.Key, - Items = g.Select(p => new PermissionItem - { - Value = p, - Selected = selected.Contains(p) - }).ToList() - }) - .OrderBy(x => x.Name) - .ToList(); - } - - private void ToggleGroup(PermissionGroup group, bool value) - { - foreach (var item in group.Items) - item.Selected = value; - } - - private void TogglePermission(PermissionItem item, bool value) - { - item.Selected = value; - } - - private bool? GetGroupState(PermissionGroup group) - { - var selected = group.Items.Count(x => x.Selected); - - if (selected == 0) - return false; - - if (selected == group.Items.Count) - return true; - - return null; - } - - private async Task Save() - { - var permissions = _groups.SelectMany(g => g.Items).Where(x => x.Selected).Select(x => Permission.From(x.Value)).ToList(); - - var req = new SetRolePermissionsRequest - { - RoleId = Role.Id, - Permissions = permissions - }; - - var result = await UAuthClient.Authorization.SetRolePermissionsAsync(req); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "Failed to update permissions", Severity.Error); - return; - } - - var result2 = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery() { Search = Role.Name }); - if (result2.Value?.Items is not null) - { - Role = result2.Value.Items.First(); - } - - Snackbar.Add("Permissions updated", Severity.Success); - RefreshUI(); - } - - private void RefreshUI() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - foreach (var group in _groups) - { - foreach (var item in group.Items) - { - item.Selected = selected.Contains(item.Value); - } - } - - StateHasChanged(); - } - - private void Cancel() => MudDialog.Cancel(); - - private class PermissionGroup - { - public string Name { get; set; } = ""; - public List Items { get; set; } = new(); - } - - private class PermissionItem - { - public string Value { get; set; } = ""; - public bool Selected { get; set; } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ResetDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ResetDialog.razor.cs deleted file mode 100644 index 0cbbd926..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/ResetDialog.razor.cs +++ /dev/null @@ -1,40 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class ResetDialog -{ - private bool _resetRequested = false; - private string? _identifier; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task RequestResetAsync() - { - var request = new BeginResetCredentialRequest - { - CredentialType = CredentialType.Password, - ResetCodeType = ResetCodeType.Code, - Identifier = _identifier ?? string.Empty - }; - - var result = await UAuthClient.Credentials.BeginResetAsync(request); - if (!result.IsSuccess || result.Value is null) - { - Snackbar.Add(result.ErrorText ?? "Failed to request credential reset.", Severity.Error); - return; - } - - _resetRequested = true; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor deleted file mode 100644 index b78db16f..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/RoleDialog.razor +++ /dev/null @@ -1,81 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - - Role Management - Manage system roles - - - - - - - - Roles - - - - - - - - - - - @GetPermissionCount(context.Item) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor deleted file mode 100644 index 8ecf2a15..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/SessionDialog.razor +++ /dev/null @@ -1,217 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Session Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_chainDetail is not null) - { - - - - Device Details - - - - @if (!_chainDetail.IsRevoked) - { - - Revoke Device - - } - - - - - - - Device Type - @_chainDetail.DeviceType - - - - Platform - @_chainDetail.Platform - - - - Operating System - @_chainDetail.OperatingSystem - - - - Browser - @_chainDetail.Browser - - - - Created - @_chainDetail.CreatedAt.ToLocalTime() - - - - Last Seen - @_chainDetail.LastSeenAt.ToLocalTime() - - - - State - - @_chainDetail.State - - - - - Active Session - @_chainDetail.ActiveSessionId - - - - Rotation Count - @_chainDetail.RotationCount - - - - Touch Count - @_chainDetail.TouchCount - - - - - - Session History - - - - Session Id - Created - Expires - Status - - - - @context.SessionId - @context.CreatedAt.ToLocalTime() - @context.ExpiresAt.ToLocalTime() - - @if (context.IsRevoked) - { - Revoked - } - else - { - Active - } - - - - - } - else - { - - Logout All Devices - @if (UserKey == null) - { - Logout Other Devices - } - Revoke All Devices - @if (UserKey == null) - { - Revoke Other Devices - } - - - - Sessions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.ChainId - - - - Created At - @context.Item.CreatedAt - - - - Touch Count - @context.Item.TouchCount - - - - Rotation Count - @context.Item.RotationCount - - - - - - - - - } - - - Cancel - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor deleted file mode 100644 index 52b9c527..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserDetailDialog.razor +++ /dev/null @@ -1,75 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorServer.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - @_user?.UserKey.Value - - - - - - - - Display Name - @_user?.DisplayName - - - - Username - @_user?.UserName - - - - Email - @_user?.PrimaryEmail - - - - Phone - @_user?.PrimaryPhone - - - - Created - @_user?.CreatedAt?.ToLocalTime() - - - - Status - @_user?.Status - - - @foreach (var s in Enum.GetValues()) - { - @s - } - - Change - - - - - - - - Management - - Sessions - Profile - Identifiers - Credentials - Roles - - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor deleted file mode 100644 index 6e754848..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor +++ /dev/null @@ -1,49 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - - User Roles - UserKey: @UserKey.Value - - - - - Assigned Roles - - @if (_roles.Count == 0) - { - No roles assigned - } - - - @foreach (var role in _roles) - { - @role - } - - - - - Add Role - - - - @foreach (var role in _allRoles) - { - @role.Name - } - - - Add - - - - - - Close - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor.cs deleted file mode 100644 index 21683f5b..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Dialogs/UserRoleDialog.razor.cs +++ /dev/null @@ -1,124 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; - -public partial class UserRoleDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } = default!; - - private List _roles = new(); - private List _allRoles = new(); - - private string? _selectedRole; - - protected override async Task OnInitializedAsync() - { - await LoadRoles(); - } - - private async Task LoadRoles() - { - var userRoles = await UAuthClient.Authorization.GetUserRolesAsync(UserKey); - - if (userRoles.IsSuccess && userRoles.Value != null) - _roles = userRoles.Value.Roles.Items.Select(x => x.Name).ToList(); - - var roles = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery - { - PageNumber = 1, - PageSize = 200 - }); - - if (roles.IsSuccess && roles.Value != null) - _allRoles = roles.Value.Items.ToList(); - } - - private async Task AddRole() - { - if (string.IsNullOrWhiteSpace(_selectedRole)) - return; - - var request = new AssignRoleRequest - { - UserKey = UserKey, - RoleName = _selectedRole - }; - - var result = await UAuthClient.Authorization.AssignRoleToUserAsync(request); - - if (result.IsSuccess) - { - _roles.Add(_selectedRole); - Snackbar.Add("Role assigned", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - - _selectedRole = null; - } - - private async Task RemoveRole(string role) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Remove Role", - $"Remove {role} from user?", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - - if (role == "Admin") - { - var confirm2 = await DialogService.ShowMessageBoxAsync( - "Are You Sure", - "You are going to remove admin role. This action may cause the application unuseable.", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm2 != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - } - - var request = new RemoveRoleRequest - { - UserKey = UserKey, - RoleName = role - }; - - var result = await UAuthClient.Authorization.RemoveRoleFromUserAsync(request); - - if (result.IsSuccess) - { - _roles.Remove(role); - Snackbar.Add("Role removed.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private void Close() => MudDialog.Close(); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor index 7239bf28..1251541a 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor @@ -1,61 +1,8 @@ @inherits LayoutComponentBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav - - - - UltimateAuth - - Blazor Server Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
+ + @Body +
diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/AuthorizedTestPage.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/AuthorizedTestPage.razor index 0b3772f8..0a953043 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/AuthorizedTestPage.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/AuthorizedTestPage.razor @@ -1,32 +1,4 @@ @page "/authorized-test" -@using CodeBeam.UltimateAuth.Core.Defaults @attribute [UAuthAuthorize] -@inherits UAuthPageBase - - - - - - Everything is Ok - - - If you see this section, it means you succesfully logged in. - - - - Go Home Page - - - - - - This is admin view content. - - - - UltimateAuth protects this resource based on your session and permissions. - - - - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor index 0e90fd7a..3e74e98b 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor @@ -1,444 +1,4 @@ @page "/home" @attribute [UAuthAuthorize] -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject UAuthClientDiagnostics Diagnostics -@inject AuthenticationStateProvider AuthStateProvider -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@using System.Security.Claims -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Custom -@using Microsoft.AspNetCore.Authorization - -@if (AuthState?.Identity?.UserStatus == UserStatus.SelfSuspended) -{ - - - - Your account is suspended. Please active it before continue. - - - - Set Active - Logout - - - - return; -} - -@if (AuthState?.Identity?.UserStatus == UserStatus.Suspended) -{ - - - - Your account is suspended. Please contact with administrator. - - - - Logout - - - - return; -} - - - - - - - - - - - Session - - - - - - - Validate - - - - - - Manual Refresh - - - - - - Logout - - - - - - Account - - - - - Manage Sessions - - - - Manage Profile - - - - Manage Identifiers - - - - Manage Credentials - - - - Suspend | Delete Account - - - - Admin - - - - - - - - - @if (_showAdminPreview) - { - - Admin operations are shown for preview. Sign in as an Admin to execute them. - - } - - @if (AuthState?.IsInRole("Admin") == true || _showAdminPreview) - { - - - - @* *@ - @* *@ - User Management - @* *@ - - - - - - @* *@ - Role Management - @* *@ - - - - } - - - - - - - - - - - @((AuthState?.Identity?.DisplayName ?? "?").Substring(0, Math.Min(2, (AuthState?.Identity?.DisplayName ?? "?").Length))) - - - - @AuthState?.Identity?.DisplayName - - @foreach (var role in AuthState?.Claims?.Roles ?? Enumerable.Empty()) - { - - @role - - } - - - - - - - - - - @if (_selectedAuthState == "UAuthState") - { - - -
- - - Tenant - - @AuthState?.Identity?.Tenant.Value -
- -
- - -
- - - User Id - - @AuthState?.Identity?.UserKey.Value -
-
- - -
- - - Authenticated - - @(AuthState?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - Session State - - @AuthState?.Identity?.SessionState?.ToDescriptionString() -
-
- - -
- - - Username - - @AuthState?.Identity?.PrimaryUserName -
-
- - -
- - - Display Name - - @AuthState?.Identity?.DisplayName -
-
- - - - - - - Email - - @AuthState?.Identity?.PrimaryEmail - - - - - - Phone - - @AuthState?.Identity?.PrimaryPhone - - - - - - - - Authenticated At - - @* TODO: Add IUAuthDateTimeFormatter *@ - @FormatLocalTime(AuthState?.Identity?.AuthenticatedAt) - - - - - - Last Validated At - - @* TODO: Validation call should update last validated at *@ - @FormatLocalTime(AuthState?.LastValidatedAt) - -
- } - else if (_selectedAuthState == "AspNetCoreState") - { - - -
- - - Authenticated - - @(_aspNetCoreState?.Identity?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - User Id - - @_aspNetCoreState?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value -
-
- - -
- - - Username - - @_aspNetCoreState?.Identity?.Name -
-
- - -
- - - Authentication Type - - @_aspNetCoreState?.Identity?.AuthenticationType -
-
-
- } -
-
-
- - - - - - @GetHealthText() - - - Lifecycle - - - - - - Started - @Diagnostics.StartCount - - @if (Diagnostics.StartedAt is not null) - { - - - - @FormatRelative(Diagnostics.StartedAt) - - - } - - - - - Stopped - @Diagnostics.StopCount - - - - - - Terminated - @Diagnostics.TerminatedCount - - @if (Diagnostics.TerminatedAt is not null) - { - - - - - @FormatRelative(Diagnostics.TerminatedAt) - - - - } - - - - - - Refresh Metrics - - - - - - - Total Attempts - @Diagnostics.RefreshAttemptCount - - - - - - - Success - - @Diagnostics.RefreshSuccessCount - - - - - - Automatic - @Diagnostics.AutomaticRefreshCount - - - - - - Manual - @Diagnostics.ManualRefreshCount - - - - - - Touched/Rotated - @Diagnostics.RefreshTouchedCount / @Diagnostics.RefreshRotatedCount - - - - - - No-Op - @Diagnostics.RefreshNoOpCount - - - - - - Reauth Required - @Diagnostics.RefreshReauthRequiredCount - - - - - - - -
-
-
+ diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor.cs deleted file mode 100644 index 415e586a..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor.cs +++ /dev/null @@ -1,222 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Blazor; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Common; -using CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Dialogs; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components.Authorization; -using MudBlazor; -using System.Security.Claims; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; - -public partial class Home : UAuthPageBase -{ - private string _selectedAuthState = "UAuthState"; - private ClaimsPrincipal? _aspNetCoreState; - - private bool _showAdminPreview = false; - - protected override async Task OnInitializedAsync() - { - var initial = await AuthStateProvider.GetAuthenticationStateAsync(); - _aspNetCoreState = initial.User; - AuthStateProvider.AuthenticationStateChanged += OnAuthStateChanged; - Diagnostics.Changed += OnDiagnosticsChanged; - } - - private void OnAuthStateChanged(Task task) - { - _ = HandleAuthStateChangedAsync(task); - } - - private async Task HandleAuthStateChangedAsync(Task task) - { - try - { - var state = await task; - _aspNetCoreState = state.User; - await InvokeAsync(StateHasChanged); - } - catch - { - - } - } - - private void OnDiagnosticsChanged() - { - InvokeAsync(StateHasChanged); - } - - private async Task Logout() => await UAuthClient.Flows.LogoutAsync(); - - private async Task RefreshSession() => await UAuthClient.Flows.RefreshAsync(false); - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private Color GetHealthColor() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return Color.Warning; - - if (Diagnostics.TerminatedCount > 0) - return Color.Error; - - return Color.Success; - } - - private string GetHealthText() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return "Reauthentication Required"; - - if (Diagnostics.TerminatedCount > 0) - return "Session Terminated"; - - return "Healthy"; - } - - private string? FormatRelative(DateTimeOffset? utc) - { - if (utc is null) - return null; - - var diff = DateTimeOffset.UtcNow - utc.Value; - - if (diff.TotalSeconds < 5) - return "just now"; - - if (diff.TotalSeconds < 60) - return $"{(int)diff.Seconds} secs ago"; - - if (diff.TotalMinutes < 60) - return $"{(int)diff.TotalMinutes} min ago"; - - if (diff.TotalHours < 24) - return $"{(int)diff.TotalHours} hrs ago"; - - return utc.Value.ToLocalTime().ToString("dd MMM yyyy"); - } - - private string? FormatLocalTime(DateTimeOffset? utc) - { - return utc?.ToLocalTime().ToString("dd MMM yyyy • HH:mm:ss"); - } - - private async Task OpenProfileDialog() - { - await DialogService.ShowAsync("Manage Profile", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifierDialog() - { - await DialogService.ShowAsync("Manage Identifiers", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenSessionDialog() - { - await DialogService.ShowAsync("Manage Sessions", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentialDialog() - { - await DialogService.ShowAsync("Session Diagnostics", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenAccountStatusDialog() - { - await DialogService.ShowAsync("Manage Account", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.ExtraSmall)); - } - - private async Task OpenUserDialog() - { - await DialogService.ShowAsync("User Management", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.Large)); - } - - private async Task OpenRoleDialog() - { - await DialogService.ShowAsync("Role Management", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private DialogParameters GetDialogParameters() - { - return new DialogParameters - { - ["AuthState"] = AuthState - }; - } - - private async Task SetAccountActiveAsync() - { - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.Active }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Account activated successfully.", Severity.Success); - } - else - { - Snackbar.Add(result?.Problem?.Detail ?? result?.Problem?.Title ?? "Activation failed.", Severity.Error); - } - } - - public override void Dispose() - { - base.Dispose(); - AuthStateProvider.AuthenticationStateChanged -= OnAuthStateChanged; - Diagnostics.Changed -= OnDiagnosticsChanged; - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor index 1e4a9016..a02d91bf 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor @@ -1,4 +1,3 @@ @page "/" -@inject NavigationManager Nav -@inject AuthenticationStateProvider AuthProvider + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor.cs deleted file mode 100644 index ab16ba5e..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/LandingPage.razor.cs +++ /dev/null @@ -1,17 +0,0 @@ -using CodeBeam.UltimateAuth.Core.Defaults; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; - -public partial class LandingPage -{ - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (!firstRender) - return; - - var state = await AuthProvider.GetAuthenticationStateAsync(); - var isAuthenticated = state.User.Identity?.IsAuthenticated == true; - - Nav.NavigateTo(isAuthenticated ? "/home" : $"{UAuthConstants.Routes.LoginRedirect}?fresh=true"); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor index 5eec659a..65d20ded 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Login.razor @@ -1,126 +1,4 @@ @page "/login" @attribute [UAuthLoginPage] -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor deleted file mode 100644 index d8eb7138..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor +++ /dev/null @@ -1,27 +0,0 @@ -@inject NavigationManager Nav - - - - - - - Access Denied - - - You don’t have permission to view this page. - If you think this is a mistake, sign in with a different account or request access. - - - - Sign In - Go Back - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor.cs deleted file mode 100644 index 9d05edad..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/NotAuthorized.razor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; - -public partial class NotAuthorized -{ - private string LoginHref - { - get - { - var returnUrl = Uri.EscapeDataString(Nav.ToBaseRelativePath(Nav.Uri)); - return $"/login?returnUrl=/{returnUrl}"; - } - } - - private void GoBack() => Nav.NavigateTo("/", replace: false); -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor index 20b38b75..48326f69 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor @@ -1,60 +1,3 @@ @page "/register" -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor.cs deleted file mode 100644 index 6adc7dc6..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Register.razor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Runtime; -using CodeBeam.UltimateAuth.Users.Contracts; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; - -public partial class Register -{ - private string? _username; - private string? _password; - private string? _passwordCheck; - private string? _email; - private UAuthClientProductInfo? _productInfo; - private MudForm _form = null!; - - protected override async Task OnInitializedAsync() - { - _productInfo = ClientProductInfoProvider.Get(); - } - - private async Task HandleRegisterAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - var request = new CreateUserRequest - { - UserName = _username, - Password = _password, - Email = _email, - }; - - var result = await UAuthClient.Users.CreateAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("User created successfully.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to create user.", Severity.Error); - } - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor index 2623395b..f2c1a536 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor @@ -1,18 +1,3 @@ @page "/reset" -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - - - - - - Change Password - - - - \ No newline at end of file + diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor.cs deleted file mode 100644 index 44c1f1a0..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/ResetCredential.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Credentials.Contracts; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages; - -public partial class ResetCredential -{ - private MudForm _form = null!; - private string? _code; - private string? _newPassword; - private string? _newPasswordCheck; - - private async Task ResetPasswordAsync() - { - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Please fix the validation errors.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("Passwords do not match.", Severity.Error); - return; - } - - if (string.IsNullOrEmpty(_code) || string.IsNullOrEmpty(_newPassword) || string.IsNullOrEmpty(Identifier)) - { - Snackbar.Add("Missing required information. Please ensure you have a valid reset code and new password.", Severity.Error); - return; - } - - var request = new CompleteResetCredentialRequest - { - ResetToken = _code, - NewSecret = _newPassword, - Identifier = Identifier // Coming from UAuthFlowPageBase automatically if begin reset is successful - }; - - var result = await UAuthClient.Credentials.CompleteResetAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Credential reset successfully. Please log in with your new password.", Severity.Success); - Navigation.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.Problem?.Detail ?? result.Problem?.Title ?? "Failed to reset credential. Please try again.", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Routes.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Routes.razor index 6586c3fc..312137a2 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Routes.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Routes.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UltimateAuth.Sample.BlazorServer.Components.Pages -@using CodeBeam.UltimateAuth.Sample.BlazorServer.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + \ No newline at end of file diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/_Imports.razor b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/_Imports.razor index 2c3cb6dd..8f58fb15 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/_Imports.razor +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/_Imports.razor @@ -18,5 +18,9 @@ @using CodeBeam.UltimateAuth.Client.Diagnostics @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Page +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Infrastructure/DarkModeManager.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Infrastructure/DarkModeManager.cs deleted file mode 100644 index 9afcf32f..00000000 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Infrastructure/DarkModeManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Contracts; -using CodeBeam.UltimateAuth.Client.Infrastructure; - -namespace CodeBeam.UltimateAuth.Sample.BlazorServer.Infrastructure; - -public sealed class DarkModeManager -{ - private const string StorageKey = "uauth:theme:dark"; - - private readonly IClientStorage _storage; - - public DarkModeManager(IClientStorage storage) - { - _storage = storage; - } - - public async Task InitializeAsync() - { - var value = await _storage.GetAsync(StorageScope.Local, StorageKey); - - if (bool.TryParse(value, out var parsed)) - IsDarkMode = parsed; - } - - public bool IsDarkMode { get; set; } - - public event Action? Changed; - - public async Task ToggleAsync() - { - IsDarkMode = !IsDarkMode; - - await _storage.SetAsync(StorageScope.Local, StorageKey, IsDarkMode.ToString()); - Changed?.Invoke(); - } - - public void Set(bool value) - { - if (IsDarkMode == value) - return; - - IsDarkMode = value; - Changed?.Invoke(); - } -} diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Program.cs b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Program.cs index 2e5cef70..07ae777a 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Program.cs +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Program.cs @@ -1,15 +1,17 @@ using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; -using CodeBeam.UltimateAuth.Core.Abstractions; using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Infrastructure; using CodeBeam.UltimateAuth.Credentials; using CodeBeam.UltimateAuth.InMemory; using CodeBeam.UltimateAuth.Sample.BlazorServer.Components; using CodeBeam.UltimateAuth.Sample.BlazorServer.Infrastructure; using CodeBeam.UltimateAuth.Sample.Seed.Extensions; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using CodeBeam.UltimateAuth.Server.Extensions; using CodeBeam.UltimateAuth.Users; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Infrastructure; using Microsoft.AspNetCore.HttpOverrides; using MudBlazor.Services; using MudExtensions.Services; @@ -66,13 +68,18 @@ builder.Services.AddUltimateAuthClientBlazor(o => { - o.AutoRefresh.Interval = TimeSpan.FromSeconds(5); + //o.AutoRefresh.Interval = TimeSpan.FromSeconds(5); o.Reauth.Behavior = ReauthBehavior.RaiseEvent; //o.UAuthStateRefreshMode = UAuthStateRefreshMode.Validate; }); builder.Services.AddUltimateAuthSampleSeed(); +//builder.Services.AddHttpClient(client => +//{ +// client.BaseAddress = new Uri("https://localhost:7213"); +//}); + // Customize UltimateAuth if (builder.Environment.IsDevelopment()) { diff --git a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/wwwroot/app.css b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/wwwroot/app.css index 2b9a4745..397f67d8 100644 --- a/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/wwwroot/app.css +++ b/samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/wwwroot/app.css @@ -50,94 +50,3 @@ h1:focus { border-color: #929292; } -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - -.uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; -} - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/App.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/App.razor index 783b707b..1b979547 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/App.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/App.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor deleted file mode 100644 index 2806b7d3..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor +++ /dev/null @@ -1,19 +0,0 @@ -@namespace CodeBeam.UltimateAuth.Sample -@inherits ComponentBase - - - - @if (Variant == UAuthLogoVariant.Brand) - { - - - - } - else - { - - - - } - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor.cs deleted file mode 100644 index 030d9b66..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogo.razor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace CodeBeam.UltimateAuth.Sample; - -public partial class UAuthLogo : ComponentBase -{ - [Parameter] public UAuthLogoVariant Variant { get; set; } = UAuthLogoVariant.Brand; - - [Parameter] public int Size { get; set; } = 32; - - [Parameter] public string? ShieldColor { get; set; } = "#00072d"; - [Parameter] public string? KeyColor { get; set; } = "#f6f5ae"; - - [Parameter] public string? Class { get; set; } - [Parameter] public string? Style { get; set; } - - private string BuildStyle() - { - if (Variant == UAuthLogoVariant.Mono) - return $"color: {KeyColor}; {Style}"; - - return Style ?? ""; - } - - protected string KeyPath => @" -M120.43,39.44H79.57A11.67,11.67,0,0,0,67.9,51.11V77.37 -A11.67,11.67,0,0,0,79.57,89H90.51l3.89,3.9v5.32l-3.8,3.81v81.41H99 -v-5.33h13.69V169H108.1v-3.8H99C99,150.76,111.9,153,111.9,153 -V99.79h-8V93.32L108.19,89h12.24 -A11.67,11.67,0,0,0,132.1,77.37V51.11 -A11.67,11.67,0,0,0,120.43,39.44Z - -M79.57,48.19h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.84a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.84a2.91,2.91 0 0 1 2.91,-2.92Z - -M79.57,68.62h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.83a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.83a2.91,2.91 0 0 1 2.91,-2.92Z - -M114.59,48.19h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.84a2.91,2.91 0 0 1 -2.91,2.91 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.91 -v-5.84a2.92,2.92 0 0 1 2.92,-2.92Z - -M114.59,68.62h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.83a2.91,2.91 0 0 1 -2.91,2.92 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.92 -v-5.83a2.92,2.92 0 0 1 2.92,-2.92Z -"; -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogoVariant.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogoVariant.cs deleted file mode 100644 index fe3be220..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Brand/UAuthLogoVariant.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample; - -public enum UAuthLogoVariant -{ - Brand, - Mono -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.csproj b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.csproj index db5ea39b..1ef3e632 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.csproj +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.csproj @@ -8,16 +8,15 @@ - - - - - - + + + + + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Common/UAuthDialog.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Common/UAuthDialog.cs deleted file mode 100644 index 5e52a199..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Common/UAuthDialog.cs +++ /dev/null @@ -1,29 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common; - -public static class UAuthDialog -{ - public static DialogParameters GetDialogParameters(UAuthState state, UserKey? userKey = null) - { - DialogParameters parameters = new DialogParameters(); - parameters.Add("AuthState", state); - if (userKey != null ) - { - parameters.Add("UserKey", userKey); - } - return parameters; - } - - public static DialogOptions GetDialogOptions(MaxWidth maxWidth = MaxWidth.Medium) - { - return new DialogOptions - { - MaxWidth = maxWidth, - FullWidth = true, - CloseButton = true - }; - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Custom/UAuthPageComponent.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Custom/UAuthPageComponent.razor deleted file mode 100644 index 5af543e4..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Custom/UAuthPageComponent.razor +++ /dev/null @@ -1,10 +0,0 @@ - - - @ChildContent - - - -@code { - [Parameter] - public RenderFragment? ChildContent { get; set; } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor deleted file mode 100644 index 0c91e45c..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor +++ /dev/null @@ -1,23 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - User: @AuthState?.Identity?.DisplayName - - - - - Suspend Account - - - - Delete Account - - - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor.cs deleted file mode 100644 index 0bd13951..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/AccountStatusDialog.razor.cs +++ /dev/null @@ -1,77 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class AccountStatusDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task SuspendAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to suspend your account.

- You can still active your account later. - """, - yesText: "Suspend", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Suspend process cancelled.", Severity.Info); - return; - } - - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.SelfSuspended }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("Your account suspended successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } - - private async Task DeleteAccountAsync() - { - var info = await DialogService.ShowMessageBoxAsync( - title: "Are You Sure", - markupMessage: (MarkupString) - """ - You are going to delete your account.

- This action can't be undone.

- (Actually it is, admin can handle soft deleted accounts.) - """, - yesText: "Delete", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (info != true) - { - Snackbar.Add("Deletion cancelled.", Severity.Info); - return; - } - - var result = await UAuthClient.Users.DeleteMeAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Your account deleted successfully.", Severity.Success); - MudDialog.Close(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Delete failed.", Severity.Error); - } - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor deleted file mode 100644 index 9a514935..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor +++ /dev/null @@ -1,27 +0,0 @@ -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Create User - - - - - - - - - - - - - - - - Cancel - Create - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor.cs deleted file mode 100644 index b10d7d9d..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CreateUserDialog.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class CreateUserDialog -{ - private MudForm _form = null!; - private string? _username; - private string? _email; - private string? _password; - private string? _passwordCheck; - private string? _displayName; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - private async Task CreateUserAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - if (_password != _passwordCheck) - { - Snackbar.Add("Passwords don't match.", Severity.Error); - return; - } - - var request = new CreateUserRequest - { - UserName = _username, - Email = _email, - DisplayName = _displayName, - Password = _password - }; - - var result = await UAuthClient.Users.CreateAsAdminAsync(request); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "User creation failed.", Severity.Error); - return; - } - - Snackbar.Add("User created successfully", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - - private string PasswordMatch(string? arg) => _password != arg ? "Passwords don't match." : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor deleted file mode 100644 index 660b7c3a..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor +++ /dev/null @@ -1,51 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Credential Management - User: @AuthState?.Identity?.DisplayName - - - - - @if (UserKey == null) - { - - - - } - else - { - - - Administrators can directly assign passwords to users. - However, using the credential reset flow is generally recommended for better security and auditability. - - - } - - - - - - - - - - - @(UserKey is null ? "Change Password" : "Set Password") - - - - - - Cancel - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor.cs deleted file mode 100644 index e3b5c2ed..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/CredentialDialog.razor.cs +++ /dev/null @@ -1,92 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class CredentialDialog -{ - private MudForm _form = null!; - private string? _oldPassword; - private string? _newPassword; - private string? _newPasswordCheck; - private bool _passwordMode1 = false; - private bool _passwordMode2 = false; - private bool _passwordMode3 = true; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - private async Task ChangePasswordAsync() - { - if (_form is null) - return; - - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Form is not valid.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("New password and check do not match", Severity.Error); - return; - } - - ChangeCredentialRequest request; - - if (UserKey is null) - { - request = new ChangeCredentialRequest - { - CurrentSecret = _oldPassword!, - NewSecret = _newPassword! - }; - } - else - { - request = new ChangeCredentialRequest - { - NewSecret = _newPassword! - }; - } - - UAuthResult result; - if (UserKey is null) - { - result = await UAuthClient.Credentials.ChangeMyAsync(request); - } - else - { - result = await UAuthClient.Credentials.ChangeUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Password changed successfully", Severity.Success); - _oldPassword = null; - _newPassword = null; - _newPasswordCheck = null; - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "An error occurred while changing password", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor deleted file mode 100644 index 24c9e8c9..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor +++ /dev/null @@ -1,115 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - - - - Identifiers - - - - - - - - - - - - - - - - - - - - - - - - - @if (context.Item.IsPrimary) - { - - - - } - else - { - - - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add - - - - - } - else - { -
- -
- } -
- - - Cancel - -
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor.cs deleted file mode 100644 index d0e89b89..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/IdentifierDialog.razor.cs +++ /dev/null @@ -1,311 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class IdentifierDialog -{ - private MudDataGrid? _grid; - private UserIdentifierType _newIdentifierType; - private string? _newIdentifierValue; - private bool _newIdentifierPrimary; - private bool _loading = false; - private bool _reloadQueued; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - var result = await UAuthClient.Identifiers.GetMyAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - } - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Identifiers.GetMyAsync(req); - } - else - { - res = await UAuthClient.Identifiers.GetUserAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task CommittedItemChanges(UserIdentifierInfo item) - { - UpdateUserIdentifierRequest updateRequest = new() - { - Id = item.Id, - NewValue = item.Value - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UpdateMyAsync(updateRequest); - } - else - { - result = await UAuthClient.Identifiers.UpdateUserAsync(UserKey.Value, updateRequest); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier updated successfully", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to update identifier", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task AddNewIdentifier() - { - if (string.IsNullOrEmpty(_newIdentifierValue)) - { - Snackbar.Add("Value cannot be empty", Severity.Warning); - return; - } - - AddUserIdentifierRequest request = new() - { - Type = _newIdentifierType, - Value = _newIdentifierValue, - IsPrimary = _newIdentifierPrimary - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.AddMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.AddUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier added successfully", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to add identifier", Severity.Error); - } - } - - private async Task VerifyAsync(Guid id) - { - var demoInfo = await DialogService.ShowMessageBoxAsync( - title: "Demo verification", - markupMessage: (MarkupString) - """ - This is a demo action.

- In a real app, you should verify identifiers via Email, SMS, or an Authenticator flow. - This will only mark the identifier as verified in UltimateAuth. - """, - yesText: "Verify", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (demoInfo != true) - { - Snackbar.Add("Verification cancelled", Severity.Info); - return; - } - - VerifyUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.VerifyMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.VerifyUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier verified successfully", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to verify primary identifier", Severity.Error); - } - } - - private async Task SetPrimaryAsync(Guid id) - { - SetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.SetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.SetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier set successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to set primary identifier", Severity.Error); - } - } - - private async Task UnsetPrimaryAsync(Guid id) - { - UnsetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UnsetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.UnsetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier unset successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to unset primary identifier", Severity.Error); - } - } - - private async Task DeleteIdentifier(Guid id) - { - DeleteUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.DeleteMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.DeleteUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier deleted successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to delete identifier", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor deleted file mode 100644 index 8e0df863..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor +++ /dev/null @@ -1,46 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using System.Reflection - -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Role Permissions - @Role.Name - - - - @* For Debug *@ - @* Current Permissions: @string.Join(", ", Role.Permissions) *@ - - @foreach (var group in _groups) - { - - - - - @group.Name (@group.Items.Count(x => x.Selected)/@group.Items.Count) - - - - - @foreach (var perm in group.Items) - { - - - - } - - - - } - - - - - Cancel - Save - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor.cs deleted file mode 100644 index e676d6ed..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/PermissionDialog.razor.cs +++ /dev/null @@ -1,120 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class PermissionDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public RoleInfo Role { get; set; } = default!; - - private List _groups = new(); - - protected override void OnInitialized() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - _groups = catalog - .GroupBy(p => p.Split('.')[0]) - .Select(g => new PermissionGroup - { - Name = g.Key, - Items = g.Select(p => new PermissionItem - { - Value = p, - Selected = selected.Contains(p) - }).ToList() - }) - .OrderBy(x => x.Name) - .ToList(); - } - - private void ToggleGroup(PermissionGroup group, bool value) - { - foreach (var item in group.Items) - item.Selected = value; - } - - private void TogglePermission(PermissionItem item, bool value) - { - item.Selected = value; - } - - private bool? GetGroupState(PermissionGroup group) - { - var selected = group.Items.Count(x => x.Selected); - - if (selected == 0) - return false; - - if (selected == group.Items.Count) - return true; - - return null; - } - - private async Task Save() - { - var permissions = _groups.SelectMany(g => g.Items).Where(x => x.Selected).Select(x => Permission.From(x.Value)).ToList(); - - var req = new SetRolePermissionsRequest - { - RoleId = Role.Id, - Permissions = permissions - }; - - var result = await UAuthClient.Authorization.SetRolePermissionsAsync(req); - - if (!result.IsSuccess) - { - Snackbar.Add(result.ErrorText ?? "Failed to update permissions", Severity.Error); - return; - } - - var result2 = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery() { Search = Role.Name }); - if (result2.Value?.Items is not null) - { - Role = result2.Value.Items.First(); - } - - Snackbar.Add("Permissions updated", Severity.Success); - RefreshUI(); - } - - private void RefreshUI() - { - var catalog = UAuthPermissionCatalog.GetAdminPermissions(); - var expanded = PermissionExpander.Expand(Role.Permissions, catalog); - var selected = expanded.Select(x => x.Value).ToHashSet(); - - foreach (var group in _groups) - { - foreach (var item in group.Items) - { - item.Selected = selected.Contains(item.Value); - } - } - - StateHasChanged(); - } - - private void Cancel() => MudDialog.Cancel(); - - private class PermissionGroup - { - public string Name { get; set; } = ""; - public List Items { get; set; } = new(); - } - - private class PermissionItem - { - public string Value { get; set; } = ""; - public bool Selected { get; set; } - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor deleted file mode 100644 index a36af169..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor +++ /dev/null @@ -1,103 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - - - - - - Name - - - - - - - - - - - - - - - - - - - Personal - - - - - - - - - - - - - - - - - - - Localization - - - - - - - - - - - @foreach (var tz in TimeZoneInfo.GetSystemTimeZones()) - { - @tz.Id - @tz.DisplayName - } - - - - - - - - - - } - else - { -
- -
- } -
- - Cancel - Save - -
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor.cs deleted file mode 100644 index 8fd1ba9d..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ProfileDialog.razor.cs +++ /dev/null @@ -1,116 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class ProfileDialog -{ - private MudForm? _form; - private string? _firstName; - private string? _lastName; - private string? _displayName; - private DateTime? _birthDate; - private string? _gender; - private string? _bio; - private string? _language; - private string? _timeZone; - private string? _culture; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.GetMeAsync(); - } - else - { - result = await UAuthClient.Users.GetUserAsync(UserKey.Value); - } - - if (result.IsSuccess && result.Value is not null) - { - var p = result.Value; - - _firstName = p.FirstName; - _lastName = p.LastName; - _displayName = p.DisplayName; - - _gender = p.Gender; - _birthDate = p.BirthDate?.ToDateTime(TimeOnly.MinValue); - _bio = p.Bio; - - _language = p.Language; - _timeZone = p.TimeZone; - _culture = p.Culture; - } - _loaded = true; - } - - private async Task SaveAsync() - { - if (AuthState is null || AuthState.Identity is null) - { - Snackbar.Add("No AuthState found.", Severity.Error); - return; - } - - if (_form is not null) - { - await _form.ValidateAsync(); - if (!_form.IsValid) - return; - } - - var request = new UpdateProfileRequest - { - FirstName = _firstName, - LastName = _lastName, - DisplayName = _displayName, - BirthDate = _birthDate.HasValue ? DateOnly.FromDateTime(_birthDate.Value) : null, - Gender = _gender, - Bio = _bio, - Language = _language, - TimeZone = _timeZone, - Culture = _culture - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.UpdateMyProfileAsync(request); - } - else - { - result = await UAuthClient.Users.UpdateUserProfileAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Profile updated", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to update profile", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor deleted file mode 100644 index 8d4c90d3..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor +++ /dev/null @@ -1,37 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Reset Credential - - - - - - This is a demonstration of how to implement a credential reset flow. - In a production application, you should use reset token or code in email, SMS etc. verification steps. - - - Reset request always returns ok even with not found users due to security reasons. - - - Request Reset - @if (_resetRequested) - { - Your reset code is on the server console. - Use Reset Code - } - - - - - Close - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor.cs deleted file mode 100644 index eafbd881..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResetDialog.razor.cs +++ /dev/null @@ -1,40 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Credentials.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class ResetDialog -{ - private bool _resetRequested = false; - private string? _identifier; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private async Task RequestResetAsync() - { - var request = new BeginResetCredentialRequest - { - CredentialType = CredentialType.Password, - ResetCodeType = ResetCodeType.Code, - Identifier = _identifier ?? string.Empty - }; - - var result = await UAuthClient.Credentials.BeginResetAsync(request); - if (!result.IsSuccess || result.Value is null) - { - Snackbar.Add(result.ErrorText ?? "Failed to request credential reset.", Severity.Error); - return; - } - - _resetRequested = true; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor deleted file mode 100644 index fe0ebb2a..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor +++ /dev/null @@ -1,54 +0,0 @@ -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.ResourceApi -@inject ProductApiService Api -@inject ISnackbar Snackbar - - - - - Resource Api - Sample demonstration of a resource. - - - - Reload - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add - - - - - - - \ No newline at end of file diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor.cs deleted file mode 100644 index 33ddb1cc..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/ResourceApiDialog.razor.cs +++ /dev/null @@ -1,95 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.ResourceApi; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class ResourceApiDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - private List _products = new List(); - private string? _newName = null; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - _products = (await Api.GetAllAsync()).Value ?? new(); - StateHasChanged(); - } - } - - private async Task CommittedItemChanges(SampleProduct item) - { - var result = await Api.UpdateAsync(item.Id, item); - - if (result.IsSuccess) - { - Snackbar.Add("Product updated successfully", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to update product.", Severity.Error); - } - - return DataGridEditFormAction.Close; - } - - private async Task GetProducts() - { - var result = await Api.GetAllAsync(); - - if (result.IsSuccess) - { - _products = result.Value ?? new(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Process failed.", Severity.Error); - } - } - - private async Task CreateProduct() - { - var product = new SampleProduct - { - Name = _newName - }; - - var result = await Api.CreateAsync(product); - - if (result.IsSuccess) - { - Snackbar.Add("New product created."); - _products = (await Api.GetAllAsync()).Value ?? new(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Process failed.", Severity.Error); - } - } - - private async Task DeleteProduct(int id) - { - var result = await Api.DeleteAsync(id); - - if (result.IsSuccess) - { - Snackbar.Add("Product deleted succesfully.", Severity.Success); - _products = (await Api.GetAllAsync()).Value ?? new(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Process failed.", Severity.Error); - } - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor deleted file mode 100644 index bfcf9428..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor +++ /dev/null @@ -1,90 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - - Role Management - Manage system roles - - - - @if (_loaded) - { - - - - - Roles - - - - - - - - - - - @GetPermissionCount(context.Item) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - } - else - { -
- -
- } -
- - - Close - -
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor.cs deleted file mode 100644 index 22c6ea7d..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/RoleDialog.razor.cs +++ /dev/null @@ -1,176 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class RoleDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _newRoleName; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new RoleQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Authorization.QueryRolesAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task CommittedItemChanges(RoleInfo role) - { - var req = new RenameRoleRequest - { - Id = role.Id, - Name = role.Name - }; - - var result = await UAuthClient.Authorization.RenameRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add("Role renamed", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Rename failed", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task CreateRole() - { - if (string.IsNullOrWhiteSpace(_newRoleName)) - { - Snackbar.Add("Role name required.", Severity.Warning); - return; - } - - var req = new CreateRoleRequest - { - Name = _newRoleName - }; - - var res = await UAuthClient.Authorization.CreateRoleAsync(req); - - if (res.IsSuccess) - { - Snackbar.Add("Role created.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(res.ErrorText ?? "Creation failed.", Severity.Error); - } - } - - private async Task DeleteRole(RoleId roleId) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Delete role", - "Are you sure?", - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - return; - - var req = new DeleteRoleRequest() { Id = roleId }; - var result = await UAuthClient.Authorization.DeleteRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add($"Role deleted, assignments removed from {result.Value?.RemovedAssignments.ToString() ?? "unknown"} users.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Deletion failed.", Severity.Error); - } - } - - private async Task EditPermissions(RoleInfo role) - { - var dialog = await DialogService.ShowAsync( - "Edit Permissions", - new DialogParameters - { - { nameof(PermissionDialog.Role), role } - }, - new DialogOptions - { - CloseButton = true, - MaxWidth = MaxWidth.Large, - FullWidth = true - }); - - var result = await dialog.Result; - await ReloadAsync(); - } - - private async Task ReloadAsync() - { - _loading = true; - await Task.Delay(300); - if (_grid is null) - return; - - await _grid.ReloadServerData(); - _loading = false; - } - - private int GetPermissionCount(RoleInfo role) - { - var expanded = PermissionExpander.Expand(role.Permissions, UAuthPermissionCatalog.GetAdminPermissions()); - return expanded.Count; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor deleted file mode 100644 index e5ee0c4d..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor +++ /dev/null @@ -1,226 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Session Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - @if (_chainDetail is not null) - { - - - - Device Details - - - - @if (!_chainDetail.IsRevoked) - { - - Revoke Device - - } - - - - - - - Device Type - @_chainDetail.DeviceType - - - - Platform - @_chainDetail.Platform - - - - Operating System - @_chainDetail.OperatingSystem - - - - Browser - @_chainDetail.Browser - - - - Created - @_chainDetail.CreatedAt.ToLocalTime() - - - - Last Seen - @_chainDetail.LastSeenAt.ToLocalTime() - - - - State - - @_chainDetail.State - - - - - Active Session - @_chainDetail.ActiveSessionId - - - - Rotation Count - @_chainDetail.RotationCount - - - - Touch Count - @_chainDetail.TouchCount - - - - - - Session History - - - - Session Id - Created - Expires - Status - - - - @context.SessionId - @context.CreatedAt.ToLocalTime() - @context.ExpiresAt.ToLocalTime() - - @if (context.IsRevoked) - { - Revoked - } - else - { - Active - } - - - - - } - else - { - - Logout All Devices - @if (UserKey == null) - { - Logout Other Devices - } - Revoke All Devices - @if (UserKey == null) - { - Revoke Other Devices - } - - - - Sessions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.ChainId - - - - Created At - @context.Item.CreatedAt - - - - Touch Count - @context.Item.TouchCount - - - - Rotation Count - @context.Item.RotationCount - - - - - - - - - } - } - else - { -
- -
- } -
- - Cancel - -
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor.cs deleted file mode 100644 index 1aaceacb..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/SessionDialog.razor.cs +++ /dev/null @@ -1,286 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class SessionDialog -{ - private MudDataGrid? _grid; - private bool _loading = false; - private bool _reloadQueued; - private SessionChainDetail? _chainDetail; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - var result = await UAuthClient.Sessions.GetMyChainsAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - } - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Sessions.GetMyChainsAsync(req); - } - else - { - res = await UAuthClient.Sessions.GetUserChainsAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task LogoutAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutAllMyDevicesAsync(); - } - else - { - result = await UAuthClient.Flows.LogoutAllUserDevicesAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task LogoutOthersAsync() - { - var result = await UAuthClient.Flows.LogoutMyOtherDevicesAsync(); - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of other devices.", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout", Severity.Error); - } - } - - private async Task LogoutDeviceAsync(SessionChainId chainId) - { - LogoutDeviceRequest request = new() { ChainId = chainId }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutMyDeviceAsync(request); - } - else - { - result = await UAuthClient.Flows.LogoutUserDeviceAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of device.", Severity.Success); - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeAllMyChainsAsync(); - } - else - { - result = await UAuthClient.Sessions.RevokeAllUserChainsAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeOthersAsync() - { - var result = await UAuthClient.Sessions.RevokeMyOtherChainsAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Revoked all other devices.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeChainAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeMyChainAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.RevokeUserChainAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - Snackbar.Add("Device revoked successfully.", Severity.Success); - - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task ShowChainDetailsAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.GetMyChainDetailAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.GetUserChainDetailAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - _chainDetail = result.Value; - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to fetch chain details.", Severity.Error); - _chainDetail = null; - } - } - - private void ClearDetail() - { - _chainDetail = null; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor deleted file mode 100644 index b8f511f8..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor +++ /dev/null @@ -1,75 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - @_user?.UserKey.Value - - - - - - - - Display Name - @_user?.DisplayName - - - - Username - @_user?.UserName - - - - Email - @_user?.PrimaryEmail - - - - Phone - @_user?.PrimaryPhone - - - - Created - @_user?.CreatedAt?.ToLocalTime() - - - - Status - @_user?.Status - - - @foreach (var s in Enum.GetValues()) - { - @s - } - - Change - - - - - - - - Management - - Sessions - Profile - Identifiers - Credentials - Roles - - - - - - Close - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor.cs deleted file mode 100644 index 5d3e3455..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserDetailDialog.razor.cs +++ /dev/null @@ -1,100 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class UserDetailDialog -{ - private UserView? _user; - private AdminAssignableUserStatus _status; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - var result = await UAuthClient.Users.GetUserAsync(UserKey); - - if (result.IsSuccess) - { - _user = result.Value; - _status = _user?.Status.ToAdminAssignableUserStatus() ?? AdminAssignableUserStatus.Unknown; - } - } - - private async Task OpenSessions() - { - await DialogService.ShowAsync("Session Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenProfile() - { - await DialogService.ShowAsync("Profile Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifiers() - { - await DialogService.ShowAsync("Identifier Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentials() - { - await DialogService.ShowAsync("Credentials", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenRoles() - { - await DialogService.ShowAsync("Roles", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task ChangeStatusAsync() - { - if (_user is null) - return; - - ChangeUserStatusAdminRequest request = new() - { - NewStatus = _status, - }; - - var result = await UAuthClient.Users.ChangeUserStatusAsync(_user.UserKey, request); - - if (result.IsSuccess) - { - Snackbar.Add("User status updated", Severity.Success); - _user = _user with { Status = _status.ToUserStatus() }; - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private Color GetStatusColor(UserStatus? status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor deleted file mode 100644 index 6e754848..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor +++ /dev/null @@ -1,49 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - - User Roles - UserKey: @UserKey.Value - - - - - Assigned Roles - - @if (_roles.Count == 0) - { - No roles assigned - } - - - @foreach (var role in _roles) - { - @role - } - - - - - Add Role - - - - @foreach (var role in _allRoles) - { - @role.Name - } - - - Add - - - - - - Close - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor.cs deleted file mode 100644 index e89d60ff..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UserRoleDialog.razor.cs +++ /dev/null @@ -1,124 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Domain; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class UserRoleDialog -{ - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } = default!; - - private List _roles = new(); - private List _allRoles = new(); - - private string? _selectedRole; - - protected override async Task OnInitializedAsync() - { - await LoadRoles(); - } - - private async Task LoadRoles() - { - var userRoles = await UAuthClient.Authorization.GetUserRolesAsync(UserKey); - - if (userRoles.IsSuccess && userRoles.Value != null) - _roles = userRoles.Value.Roles.Items.Select(x => x.Name).ToList(); - - var roles = await UAuthClient.Authorization.QueryRolesAsync(new RoleQuery - { - PageNumber = 1, - PageSize = 200 - }); - - if (roles.IsSuccess && roles.Value != null) - _allRoles = roles.Value.Items.ToList(); - } - - private async Task AddRole() - { - if (string.IsNullOrWhiteSpace(_selectedRole)) - return; - - var request = new AssignRoleRequest - { - UserKey = UserKey, - RoleName = _selectedRole - }; - - var result = await UAuthClient.Authorization.AssignRoleToUserAsync(request); - - if (result.IsSuccess) - { - _roles.Add(_selectedRole); - Snackbar.Add("Role assigned", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - - _selectedRole = null; - } - - private async Task RemoveRole(string role) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Remove Role", - $"Remove {role} from user?", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - - if (role == "Admin") - { - var confirm2 = await DialogService.ShowMessageBoxAsync( - "Are You Sure", - "You are going to remove admin role. This action may cause the application unuseable.", - yesText: "Remove", - noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm2 != true) - { - Snackbar.Add("Role remove process cancelled.", Severity.Info); - return; - } - } - - var request = new RemoveRoleRequest - { - UserKey = UserKey, - RoleName = role - }; - - var result = await UAuthClient.Authorization.RemoveRoleFromUserAsync(request); - - if (result.IsSuccess) - { - _roles.Remove(role); - Snackbar.Add("Role removed.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private void Close() => MudDialog.Close(); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor deleted file mode 100644 index f9df9a84..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor +++ /dev/null @@ -1,94 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - Browse, create and manage users - - - - @if (_loaded) - { - - - - - - - - - - - - - - Users - - New User - - - - - - - - - - - @context.Item.Status - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.UserKey.Value - - - - Created At - @context.Item.CreatedAt - - - - - - - - - - } - else - { -
- -
- } -
- - - Close - -
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor.cs deleted file mode 100644 index a215a013..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Components/Dialogs/UsersDialog.razor.cs +++ /dev/null @@ -1,188 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; - -public partial class UsersDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _search; - private bool _reloadQueued; - private UserStatus? _statusFilter; - private bool _loaded; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - StateHasChanged(); - } - } - - private async Task> LoadUsers(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new UserQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - Search = _search, - Status = _statusFilter, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Users.QueryAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed to load users.", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task OnStatusChanged(UserStatus? status) - { - _statusFilter = status; - await ReloadAsync(); - } - - private async Task OpenUser(UserKey userKey) - { - var dialog = await DialogService.ShowAsync("User", UAuthDialog.GetDialogParameters(AuthState, userKey), UAuthDialog.GetDialogOptions()); - await dialog.Result; - await ReloadAsync(); - } - - private async Task OpenCreateUser() - { - var dialog = await DialogService.ShowAsync( - "Create User", - new DialogOptions - { - MaxWidth = MaxWidth.Small, - FullWidth = true, - CloseButton = true - }); - - var result = await dialog.Result; - - if (result?.Canceled == false) - await ReloadAsync(); - } - - private async Task DeleteUserAsync(UserSummary user) - { - var confirm = await DialogService.ShowMessageBoxAsync( - title: "Delete user", - markupMessage: (MarkupString)$""" - Are you sure you want to delete {user.DisplayName ?? user.UserName ?? user.PrimaryEmail ?? user.UserKey}? -

- This operation is intended for admin usage. - """, - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions - { - MaxWidth = MaxWidth.Medium, - FullWidth = true, - BackgroundClass = "uauth-blur-slight" - }); - - if (confirm != true) - return; - - var req = new DeleteUserRequest - { - Mode = DeleteMode.Soft - }; - - var result = await UAuthClient.Users.DeleteUserAsync(UserKey.Parse(user.UserKey, null), req); - - if (result.IsSuccess) - { - Snackbar.Add("User deleted successfully.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to delete user.", Severity.Error); - } - } - - private static Color GetStatusColor(UserStatus status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.SelfSuspended => Color.Warning, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Infrastructure/DarkModeManager.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Infrastructure/DarkModeManager.cs deleted file mode 100644 index de933317..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Infrastructure/DarkModeManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Contracts; -using CodeBeam.UltimateAuth.Client.Infrastructure; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Infrastructure; - -public sealed class DarkModeManager -{ - private const string StorageKey = "uauth:theme:dark"; - - private readonly IClientStorage _storage; - - public DarkModeManager(IClientStorage storage) - { - _storage = storage; - } - - public async Task InitializeAsync() - { - var value = await _storage.GetAsync(StorageScope.Local, StorageKey); - - if (bool.TryParse(value, out var parsed)) - IsDarkMode = parsed; - } - - public bool IsDarkMode { get; set; } - - public event Action? Changed; - - public async Task ToggleAsync() - { - IsDarkMode = !IsDarkMode; - - await _storage.SetAsync(StorageScope.Local, StorageKey, IsDarkMode.ToString()); - Changed?.Invoke(); - } - - public void Set(bool value) - { - if (IsDarkMode == value) - return; - - IsDarkMode = value; - Changed?.Invoke(); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor index 2788afc2..5bbc27a0 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor @@ -1,61 +1,8 @@ @inherits LayoutComponentBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav - - - - UltimateAuth - - Blazor WASM Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
+ + @Body +
diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor.cs deleted file mode 100644 index 06946b76..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Infrastructure; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Layout; - -public partial class MainLayout -{ - [CascadingParameter] - public UAuthState UAuth { get; set; } = default!; - - [CascadingParameter] - public DarkModeManager DarkModeManager { get; set; } = default!; - - private async Task Refresh() - { - await UAuthClient.Flows.RefreshAsync(); - } - - private async Task Logout() - { - await UAuthClient.Flows.LogoutAsync(); - } - - private Color GetBadgeColor() - { - if (UAuth is null || !UAuth.IsAuthenticated) - return Color.Error; - - if (UAuth.IsStale) - return Color.Warning; - - var state = UAuth.Identity?.SessionState; - - if (state is null || state == SessionState.Active) - return Color.Success; - - if (state == SessionState.Invalid) - return Color.Error; - - return Color.Warning; - } - - private void HandleSignInClick() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true); - return; - } - - GoToLoginWithReturn(); - } - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private void GoToLoginWithReturn() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login", replace: true); - return; - } - - var current = Nav.ToBaseRelativePath(uri.ToString()); - if (string.IsNullOrWhiteSpace(current)) - current = "home"; - - var returnUrl = Uri.EscapeDataString("/" + current.TrimStart('/')); - Nav.NavigateTo($"/login?returnUrl={returnUrl}", replace: true); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/AuthorizedTestPage.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/AuthorizedTestPage.razor index cf9519f6..0a953043 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/AuthorizedTestPage.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/AuthorizedTestPage.razor @@ -1,27 +1,4 @@ @page "/authorized-test" @attribute [UAuthAuthorize] -@inherits UAuthPageBase - - - - - - Everything is Ok - - - If you see this section, it means you succesfully logged in. - - - - Go Profile - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - \ No newline at end of file + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor index 8b20171f..945a4332 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor @@ -1,453 +1,4 @@ @page "/home" @attribute [UAuthAuthorize] -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject UAuthClientDiagnostics Diagnostics -@inject AuthenticationStateProvider AuthStateProvider -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@using System.Security.Claims -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Custom -@using Microsoft.AspNetCore.Authorization - -@if (AuthState?.Identity?.UserStatus == UserStatus.SelfSuspended) -{ - - - - Your account is suspended. Please active it before continue. - - - - Set Active - Logout - - - - return; -} - -@if (AuthState?.Identity?.UserStatus == UserStatus.Suspended) -{ - - - - Your account is suspended. Please contact with administrator. - - - - Logout - - - - return; -} - - - - - - - - - - - Session - - - - - - - Validate - - - - - - Manual Refresh - - - - - - Logout - - - - - - Account - - - - - Manage Sessions - - - - Manage Profile - - - - Manage Identifiers - - - - Manage Credentials - - - - Suspend | Delete Account - - - - Admin - - - - - - - - - @if (_showAdminPreview) - { - - Admin operations are shown for preview. Sign in as an Admin to execute them. - - } - - @if (AuthState?.IsInRole("Admin") == true || _showAdminPreview) - { - - - - @* *@ - @* *@ - User Management - @* *@ - - - - - - @* *@ - Role Management - @* *@ - - - - } - - - Resource Api - - - - - Manage Resource - - - - - - - - - - - - @((AuthState?.Identity?.DisplayName ?? "?").Substring(0, Math.Min(2, (AuthState?.Identity?.DisplayName ?? "?").Length))) - - - - @AuthState?.Identity?.DisplayName - - @foreach (var role in AuthState?.Claims?.Roles ?? Enumerable.Empty()) - { - - @role - - } - - - - - - - - - - @if (_selectedAuthState == "UAuthState") - { - - -
- - - Tenant - - @AuthState?.Identity?.Tenant.Value -
- -
- - -
- - - User Id - - @AuthState?.Identity?.UserKey.Value -
-
- - -
- - - Authenticated - - @(AuthState?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - Session State - - @AuthState?.Identity?.SessionState?.ToDescriptionString() -
-
- - -
- - - Username - - @AuthState?.Identity?.PrimaryUserName -
-
- - -
- - - Display Name - - @AuthState?.Identity?.DisplayName -
-
- - - - - - - Email - - @AuthState?.Identity?.PrimaryEmail - - - - - - Phone - - @AuthState?.Identity?.PrimaryPhone - - - - - - - - Authenticated At - - @* TODO: Add IUAuthDateTimeFormatter *@ - @FormatLocalTime(AuthState?.Identity?.AuthenticatedAt) - - - - - - Last Validated At - - @* TODO: Validation call should update last validated at *@ - @FormatLocalTime(AuthState?.LastValidatedAt) - -
- } - else if (_selectedAuthState == "AspNetCoreState") - { - - -
- - - Authenticated - - @(_aspNetCoreState?.Identity?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - User Id - - @_aspNetCoreState?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value -
-
- - -
- - - Username - - @_aspNetCoreState?.Identity?.Name -
-
- - -
- - - Authentication Type - - @_aspNetCoreState?.Identity?.AuthenticationType -
-
-
- } -
-
-
- - - - - - @GetHealthText() - - - Lifecycle - - - - - - Started - @Diagnostics.StartCount - - @if (Diagnostics.StartedAt is not null) - { - - - - @FormatRelative(Diagnostics.StartedAt) - - - } - - - - - Stopped - @Diagnostics.StopCount - - - - - - Terminated - @Diagnostics.TerminatedCount - - @if (Diagnostics.TerminatedAt is not null) - { - - - - - @FormatRelative(Diagnostics.TerminatedAt) - - - - } - - - - - - Refresh Metrics - - - - - - - Total Attempts - @Diagnostics.RefreshAttemptCount - - - - - - - Success - - @Diagnostics.RefreshSuccessCount - - - - - - Automatic - @Diagnostics.AutomaticRefreshCount - - - - - - Manual - @Diagnostics.ManualRefreshCount - - - - - - Touched/Rotated - @Diagnostics.RefreshTouchedCount / @Diagnostics.RefreshRotatedCount - - - - - - No-Op - @Diagnostics.RefreshNoOpCount - - - - - - Reauth Required - @Diagnostics.RefreshReauthRequiredCount - - - - - - - -
-
-
+ \ No newline at end of file diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor.cs deleted file mode 100644 index 4464b6ff..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor.cs +++ /dev/null @@ -1,227 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Blazor; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Common; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components.Authorization; -using MudBlazor; -using System.Security.Claims; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; - -public partial class Home : UAuthPageBase -{ - private string _selectedAuthState = "UAuthState"; - private ClaimsPrincipal? _aspNetCoreState; - - private bool _showAdminPreview = false; - - protected override async Task OnInitializedAsync() - { - var initial = await AuthStateProvider.GetAuthenticationStateAsync(); - _aspNetCoreState = initial.User; - AuthStateProvider.AuthenticationStateChanged += OnAuthStateChanged; - Diagnostics.Changed += OnDiagnosticsChanged; - } - - private void OnAuthStateChanged(Task task) - { - _ = HandleAuthStateChangedAsync(task); - } - - private async Task HandleAuthStateChangedAsync(Task task) - { - try - { - var state = await task; - _aspNetCoreState = state.User; - await InvokeAsync(StateHasChanged); - } - catch - { - - } - } - - private void OnDiagnosticsChanged() - { - InvokeAsync(StateHasChanged); - } - - private async Task Logout() => await UAuthClient.Flows.LogoutAsync(); - - private async Task RefreshSession() => await UAuthClient.Flows.RefreshAsync(false); - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private Color GetHealthColor() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return Color.Warning; - - if (Diagnostics.TerminatedCount > 0) - return Color.Error; - - return Color.Success; - } - - private string GetHealthText() - { - if (Diagnostics.RefreshReauthRequiredCount > 0) - return "Reauthentication Required"; - - if (Diagnostics.TerminatedCount > 0) - return "Session Terminated"; - - return "Healthy"; - } - - private string? FormatRelative(DateTimeOffset? utc) - { - if (utc is null) - return null; - - var diff = DateTimeOffset.UtcNow - utc.Value; - - if (diff.TotalSeconds < 5) - return "just now"; - - if (diff.TotalSeconds < 60) - return $"{(int)diff.Seconds} secs ago"; - - if (diff.TotalMinutes < 60) - return $"{(int)diff.TotalMinutes} min ago"; - - if (diff.TotalHours < 24) - return $"{(int)diff.TotalHours} hrs ago"; - - return utc.Value.ToLocalTime().ToString("dd MMM yyyy"); - } - - private string? FormatLocalTime(DateTimeOffset? utc) - { - return utc?.ToLocalTime().ToString("dd MMM yyyy • HH:mm:ss"); - } - - private async Task OpenProfileDialog() - { - await DialogService.ShowAsync("Manage Profile", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifierDialog() - { - await DialogService.ShowAsync("Manage Identifiers", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenSessionDialog() - { - await DialogService.ShowAsync("Manage Sessions", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentialDialog() - { - await DialogService.ShowAsync("Session Diagnostics", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenAccountStatusDialog() - { - await DialogService.ShowAsync("Manage Account", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.ExtraSmall)); - } - - private async Task OpenUserDialog() - { - await DialogService.ShowAsync("User Management", GetDialogParameters(), UAuthDialog.GetDialogOptions(MaxWidth.Large)); - } - - private async Task OpenRoleDialog() - { - await DialogService.ShowAsync("Role Management", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenResourceApiDialog() - { - await DialogService.ShowAsync("Resource Api", GetDialogParameters(), UAuthDialog.GetDialogOptions()); - } - - private DialogParameters GetDialogParameters() - { - return new DialogParameters - { - ["AuthState"] = AuthState - }; - } - - private async Task SetAccountActiveAsync() - { - ChangeUserStatusSelfRequest request = new() { NewStatus = SelfAssignableUserStatus.Active }; - var result = await UAuthClient.Users.ChangeMyStatusAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Account activated successfully.", Severity.Success); - } - else - { - Snackbar.Add(result?.Problem?.Detail ?? result?.Problem?.Title ?? "Activation failed.", Severity.Error); - } - } - - public override void Dispose() - { - base.Dispose(); - AuthStateProvider.AuthenticationStateChanged -= OnAuthStateChanged; - Diagnostics.Changed -= OnDiagnosticsChanged; - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor index 1e4a9016..a02d91bf 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/LandingPage.razor @@ -1,4 +1,3 @@ @page "/" -@inject NavigationManager Nav -@inject AuthenticationStateProvider AuthProvider + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor index 595addf8..12aa98c8 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor @@ -1,134 +1,4 @@ @page "/login" @attribute [UAuthLoginPage] -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor.cs deleted file mode 100644 index 3250a476..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Login.razor.cs +++ /dev/null @@ -1,216 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Blazor; -using CodeBeam.UltimateAuth.Client.Runtime; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Components.Dialogs; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; - -public partial class Login : UAuthPageBase -{ - private string? _username; - private string? _password; - private UAuthClientProductInfo? _productInfo; - private MudTextField _usernameField = default!; - - private CancellationTokenSource? _lockoutCts; - private PeriodicTimer? _lockoutTimer; - private DateTimeOffset? _lockoutUntil; - private TimeSpan _remaining; - private bool _isLocked; - private DateTimeOffset? _lockoutStartedAt; - private TimeSpan _lockoutDuration; - private double _progressPercent; - private int? _remainingAttempts = null; - - protected override async Task OnInitializedAsync() - { - _productInfo = ClientProductInfoProvider.Get(); - } - - protected override Task OnUAuthPayloadAsync(AuthFlowPayload payload) - { - HandleLoginPayload(payload); - return Task.CompletedTask; - } - - protected override async Task OnFocusRequestedAsync() - { - await _usernameField.FocusAsync(); - } - - private void HandleLoginPayload(AuthFlowPayload payload) - { - if (payload.Flow != AuthFlowType.Login) - return; - - if (payload.Reason == AuthFailureReason.LockedOut && payload.LockoutUntilUtc is { } until) - { - _lockoutUntil = until; - StartCountdown(); - } - - _remainingAttempts = payload.RemainingAttempts; - - ShowLoginError(payload.Reason, payload.RemainingAttempts); - } - - private void ShowLoginError(AuthFailureReason? reason, int? remainingAttempts) - { - string message = reason switch - { - AuthFailureReason.InvalidCredentials when remainingAttempts is > 0 - => $"Invalid username or password. {remainingAttempts} attempt(s) remaining.", - - AuthFailureReason.InvalidCredentials - => "Invalid username or password.", - - AuthFailureReason.RequiresMfa - => "Multi-factor authentication required.", - - AuthFailureReason.LockedOut - => "Your account is locked.", - - _ => "Login failed." - }; - - Snackbar.Add(message, Severity.Error); - } - - private async Task StartPkceLogin() - { - string? returnUrl = null; - if (!string.IsNullOrEmpty(ReturnUrl)) - returnUrl = Navigation.BaseUri + ReturnUrl.TrimStart('/'); - - await UAuthClient.Flows.BeginPkceAsync(returnUrl); - } - - private async Task ProgrammaticLogin() - { - var deviceId = await DeviceIdProvider.GetOrCreateAsync(); - var request = new LoginRequest - { - Identifier = "admin", - Secret = "admin", - }; - await UAuthClient.Flows.LoginAsync(request, ReturnUrl ?? "/home"); - } - - private async Task HandleLoginResult(IUAuthTryResult result) - { - if (!result.IsSuccess) - { - if (result.Reason == AuthFailureReason.LockedOut && result.LockoutUntilUtc is { } until) - { - _lockoutUntil = until; - StartCountdown(); - } - - _remainingAttempts = result.RemainingAttempts; - ShowLoginError(result.Reason, result.RemainingAttempts); - } - } - - private async void StartCountdown() - { - if (_lockoutUntil is null) - return; - - _isLocked = true; - _lockoutStartedAt = DateTimeOffset.UtcNow; - _lockoutDuration = _lockoutUntil.Value - DateTimeOffset.UtcNow; - UpdateRemaining(); - - _lockoutCts?.Cancel(); - _lockoutCts = new CancellationTokenSource(); - - _lockoutTimer?.Dispose(); - _lockoutTimer = new PeriodicTimer(TimeSpan.FromSeconds(1)); - - try - { - while (await _lockoutTimer.WaitForNextTickAsync(_lockoutCts.Token)) - { - UpdateRemaining(); - - if (_remaining <= TimeSpan.Zero) - { - ResetLockoutState(); - await InvokeAsync(StateHasChanged); - break; - } - - await InvokeAsync(StateHasChanged); - } - } - catch (OperationCanceledException) - { - - } - } - - private void ResetLockoutState() - { - _isLocked = false; - _lockoutUntil = null; - _progressPercent = 0; - _remainingAttempts = null; - } - - private void UpdateRemaining() - { - if (_lockoutUntil is null || _lockoutStartedAt is null) - return; - - var now = DateTimeOffset.UtcNow; - - _remaining = _lockoutUntil.Value - now; - - if (_remaining <= TimeSpan.Zero) - { - _remaining = TimeSpan.Zero; - return; - } - - var elapsed = now - _lockoutStartedAt.Value; - - if (_lockoutDuration.TotalSeconds > 0) - { - var percent = 100 - (elapsed.TotalSeconds / _lockoutDuration.TotalSeconds * 100); - _progressPercent = Math.Max(0, percent); - } - } - - private async Task OpenResetDialog() - { - await DialogService.ShowAsync("Reset Credentials", GetDialogParameters(), GetDialogOptions()); - } - - private DialogOptions GetDialogOptions() - { - return new DialogOptions - { - MaxWidth = MaxWidth.Medium, - FullWidth = true, - CloseButton = true - }; - } - - private DialogParameters GetDialogParameters() - { - return new DialogParameters - { - ["AuthState"] = AuthState - }; - } - - public override void Dispose() - { - base.Dispose(); - _lockoutCts?.Cancel(); - _lockoutTimer?.Dispose(); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor deleted file mode 100644 index d8eb7138..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor +++ /dev/null @@ -1,27 +0,0 @@ -@inject NavigationManager Nav - - - - - - - Access Denied - - - You don’t have permission to view this page. - If you think this is a mistake, sign in with a different account or request access. - - - - Sign In - Go Back - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor.cs deleted file mode 100644 index f46ca21f..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/NotAuthorized.razor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; - -public partial class NotAuthorized -{ - private string LoginHref - { - get - { - var returnUrl = Uri.EscapeDataString(Nav.ToBaseRelativePath(Nav.Uri)); - return $"/login?returnUrl=/{returnUrl}"; - } - } - - private void GoBack() => Nav.NavigateTo("/", replace: false); -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor index 20b38b75..745143b0 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor @@ -1,60 +1,3 @@ @page "/register" -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor.cs deleted file mode 100644 index 8219cee3..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Register.razor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CodeBeam.UltimateAuth.Client.Runtime; -using CodeBeam.UltimateAuth.Users.Contracts; -using MudBlazor; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Pages; - -public partial class Register -{ - private string? _username; - private string? _password; - private string? _passwordCheck; - private string? _email; - private UAuthClientProductInfo? _productInfo; - private MudForm _form = null!; - - protected override async Task OnInitializedAsync() - { - _productInfo = ClientProductInfoProvider.Get(); - } - - private async Task HandleRegisterAsync() - { - await _form.ValidateAsync(); - - if (!_form.IsValid) - return; - - var request = new CreateUserRequest - { - UserName = _username, - Password = _password, - Email = _email, - }; - - var result = await UAuthClient.Users.CreateAsync(request); - if (result.IsSuccess) - { - Snackbar.Add("User created successfully.", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to create user.", Severity.Error); - } - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor index 2623395b..f2c1a536 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/ResetCredential.razor @@ -1,18 +1,3 @@ @page "/reset" -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - - - - - - Change Password - - - - \ No newline at end of file + diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Program.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Program.cs index 90c603f5..4fb69e88 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Program.cs +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Program.cs @@ -1,8 +1,8 @@ using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.Infrastructure; -using CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.ResourceApi; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor.Services; @@ -28,10 +28,10 @@ o.Login.AllowCredentialPost = true; o.Pkce.ReturnUrl = "https://localhost:6130/home"; // This application domain + path - o.AutoRefresh.Interval = TimeSpan.FromSeconds(5); + //o.AutoRefresh.Interval = TimeSpan.FromSeconds(5); }); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(sp => { diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/ProductApiService.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/ProductApiService.cs deleted file mode 100644 index f410db79..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/ProductApiService.cs +++ /dev/null @@ -1,78 +0,0 @@ -using CodeBeam.UltimateAuth.Core.Contracts; -using Microsoft.AspNetCore.Components.WebAssembly.Http; -using System.Net.Http.Json; - -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.ResourceApi; - -public class ProductApiService -{ - private readonly HttpClient _http; - - public ProductApiService(HttpClient http) - { - _http = http; - } - - private HttpRequestMessage CreateRequest(HttpMethod method, string url, object? body = null) - { - var request = new HttpRequestMessage(method, url); - request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include); - - if (body is not null) - { - request.Content = JsonContent.Create(body); - } - - return request; - } - - public Task>> GetAllAsync() - => SendAsync>(CreateRequest(HttpMethod.Get, "/api/products")); - - public Task> GetAsync(int id) - => SendAsync(CreateRequest(HttpMethod.Get, $"/api/products/{id}")); - - public Task> CreateAsync(SampleProduct product) - => SendAsync(CreateRequest(HttpMethod.Post, $"/api/products", product)); - - public Task> UpdateAsync(int id, SampleProduct product) - => SendAsync(CreateRequest(HttpMethod.Put, $"/api/products/{id}", product)); - - public Task> DeleteAsync(int id) - => SendAsync(CreateRequest(HttpMethod.Delete, $"/api/products/{id}")); - - private async Task> SendAsync(HttpRequestMessage request) - { - var response = await _http.SendAsync(request); - - var result = new UAuthResult - { - Status = (int)response.StatusCode, - IsSuccess = response.IsSuccessStatusCode - }; - - if (response.IsSuccessStatusCode) - { - result.Value = await response.Content.ReadFromJsonAsync(); - return result; - } - - result.Problem = await TryReadProblem(response); - return result; - } - - private async Task TryReadProblem(HttpResponseMessage response) - { - try - { - return await response.Content.ReadFromJsonAsync(); - } - catch - { - return new UAuthProblem - { - Title = response.ReasonPhrase - }; - } - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/SampleProduct.cs b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/SampleProduct.cs deleted file mode 100644 index bf145679..00000000 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/ResourceApi/SampleProduct.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm.ResourceApi; - -public class SampleProduct -{ - public int Id { get; set; } - public string? Name { get; set; } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/_Imports.razor b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/_Imports.razor index 9eaccb01..3826aa6f 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/_Imports.razor +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/_Imports.razor @@ -18,5 +18,9 @@ @using CodeBeam.UltimateAuth.Client.Diagnostics @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Page +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/css/app.css b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/css/app.css index 897c71bd..0fb0cf5c 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/css/app.css +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/css/app.css @@ -112,95 +112,3 @@ code { .form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { text-align: start; } - -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - - .uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; - } - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/index.html b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/index.html index 26cd7ae0..05649156 100644 --- a/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/index.html +++ b/samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/wwwroot/index.html @@ -8,6 +8,7 @@ + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor deleted file mode 100644 index 2806b7d3..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor +++ /dev/null @@ -1,19 +0,0 @@ -@namespace CodeBeam.UltimateAuth.Sample -@inherits ComponentBase - - - - @if (Variant == UAuthLogoVariant.Brand) - { - - - - } - else - { - - - - } - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor.cs deleted file mode 100644 index 030d9b66..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogo.razor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; - -namespace CodeBeam.UltimateAuth.Sample; - -public partial class UAuthLogo : ComponentBase -{ - [Parameter] public UAuthLogoVariant Variant { get; set; } = UAuthLogoVariant.Brand; - - [Parameter] public int Size { get; set; } = 32; - - [Parameter] public string? ShieldColor { get; set; } = "#00072d"; - [Parameter] public string? KeyColor { get; set; } = "#f6f5ae"; - - [Parameter] public string? Class { get; set; } - [Parameter] public string? Style { get; set; } - - private string BuildStyle() - { - if (Variant == UAuthLogoVariant.Mono) - return $"color: {KeyColor}; {Style}"; - - return Style ?? ""; - } - - protected string KeyPath => @" -M120.43,39.44H79.57A11.67,11.67,0,0,0,67.9,51.11V77.37 -A11.67,11.67,0,0,0,79.57,89H90.51l3.89,3.9v5.32l-3.8,3.81v81.41H99 -v-5.33h13.69V169H108.1v-3.8H99C99,150.76,111.9,153,111.9,153 -V99.79h-8V93.32L108.19,89h12.24 -A11.67,11.67,0,0,0,132.1,77.37V51.11 -A11.67,11.67,0,0,0,120.43,39.44Z - -M79.57,48.19h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.84a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.84a2.91,2.91 0 0 1 2.91,-2.92Z - -M79.57,68.62h5.84a2.92,2.92 0 0 1 2.92,2.92 -v5.83a2.92,2.92 0 0 1 -2.92,2.92 -h-5.84a2.91,2.91 0 0 1 -2.91,-2.92 -v-5.83a2.91,2.91 0 0 1 2.91,-2.92Z - -M114.59,48.19h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.84a2.91,2.91 0 0 1 -2.91,2.91 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.91 -v-5.84a2.92,2.92 0 0 1 2.92,-2.92Z - -M114.59,68.62h5.84a2.92,2.92 0 0 1 2.91,2.92 -v5.83a2.91,2.91 0 0 1 -2.91,2.92 -h-5.84a2.92,2.92 0 0 1 -2.92,-2.92 -v-5.83a2.92,2.92 0 0 1 2.92,-2.92Z -"; -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogoVariant.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogoVariant.cs deleted file mode 100644 index fe3be220..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Brand/UAuthLogoVariant.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CodeBeam.UltimateAuth.Sample; - -public enum UAuthLogoVariant -{ - Brand, - Mono -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/CodeBeam.UAuth.Sample.IntWasm.Client.csproj b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/CodeBeam.UAuth.Sample.IntWasm.Client.csproj index e4408ae2..1dafa9a8 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/CodeBeam.UAuth.Sample.IntWasm.Client.csproj +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/CodeBeam.UAuth.Sample.IntWasm.Client.csproj @@ -11,14 +11,13 @@ - - - - + + + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Custom/UAuthPageComponent.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Custom/UAuthPageComponent.razor deleted file mode 100644 index 5af543e4..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Custom/UAuthPageComponent.razor +++ /dev/null @@ -1,10 +0,0 @@ - - - @ChildContent - - - -@code { - [Parameter] - public RenderFragment? ChildContent { get; set; } -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor deleted file mode 100644 index 0c91e45c..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/AccountStatusDialog.razor +++ /dev/null @@ -1,23 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - User: @AuthState?.Identity?.DisplayName - - - - - Suspend Account - - - - Delete Account - - - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor deleted file mode 100644 index 660b7c3a..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/CredentialDialog.razor +++ /dev/null @@ -1,51 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Credential Management - User: @AuthState?.Identity?.DisplayName - - - - - @if (UserKey == null) - { - - - - } - else - { - - - Administrators can directly assign passwords to users. - However, using the credential reset flow is generally recommended for better security and auditability. - - - } - - - - - - - - - - - @(UserKey is null ? "Change Password" : "Set Password") - - - - - - Cancel - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor deleted file mode 100644 index 24c9e8c9..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor +++ /dev/null @@ -1,115 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - - - - Identifiers - - - - - - - - - - - - - - - - - - - - - - - - - @if (context.Item.IsPrimary) - { - - - - } - else - { - - - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add - - - - - } - else - { -
- -
- } -
- - - Cancel - -
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor.cs deleted file mode 100644 index 135cdc64..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/IdentifierDialog.razor.cs +++ /dev/null @@ -1,311 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class IdentifierDialog -{ - private MudDataGrid? _grid; - private UserIdentifierType _newIdentifierType; - private string? _newIdentifierValue; - private bool _newIdentifierPrimary; - private bool _loading = false; - private bool _reloadQueued; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - var result = await UAuthClient.Identifiers.GetMyAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - } - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Identifiers.GetMyAsync(req); - } - else - { - res = await UAuthClient.Identifiers.GetUserAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task CommittedItemChanges(UserIdentifierInfo item) - { - UpdateUserIdentifierRequest updateRequest = new() - { - Id = item.Id, - NewValue = item.Value - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UpdateMyAsync(updateRequest); - } - else - { - result = await UAuthClient.Identifiers.UpdateUserAsync(UserKey.Value, updateRequest); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier updated successfully", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to update identifier", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task AddNewIdentifier() - { - if (string.IsNullOrEmpty(_newIdentifierValue)) - { - Snackbar.Add("Value cannot be empty", Severity.Warning); - return; - } - - AddUserIdentifierRequest request = new() - { - Type = _newIdentifierType, - Value = _newIdentifierValue, - IsPrimary = _newIdentifierPrimary - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.AddMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.AddUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier added successfully", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to add identifier", Severity.Error); - } - } - - private async Task VerifyAsync(Guid id) - { - var demoInfo = await DialogService.ShowMessageBoxAsync( - title: "Demo verification", - markupMessage: (MarkupString) - """ - This is a demo action.

- In a real app, you should verify identifiers via Email, SMS, or an Authenticator flow. - This will only mark the identifier as verified in UltimateAuth. - """, - yesText: "Verify", noText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (demoInfo != true) - { - Snackbar.Add("Verification cancelled", Severity.Info); - return; - } - - VerifyUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.VerifyMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.VerifyUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier verified successfully", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to verify primary identifier", Severity.Error); - } - } - - private async Task SetPrimaryAsync(Guid id) - { - SetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.SetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.SetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier set successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to set primary identifier", Severity.Error); - } - } - - private async Task UnsetPrimaryAsync(Guid id) - { - UnsetPrimaryUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.UnsetMyPrimaryAsync(request); - } - else - { - result = await UAuthClient.Identifiers.UnsetUserPrimaryAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Primary identifier unset successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to unset primary identifier", Severity.Error); - } - } - - private async Task DeleteIdentifier(Guid id) - { - DeleteUserIdentifierRequest request = new() { Id = id }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Identifiers.DeleteMyAsync(request); - } - else - { - result = await UAuthClient.Identifiers.DeleteUserAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Identifier deleted successfully.", Severity.Success); - await ReloadAsync(); - StateHasChanged(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to delete identifier", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor deleted file mode 100644 index 8e0df863..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/PermissionDialog.razor +++ /dev/null @@ -1,46 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using System.Reflection - -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - Role Permissions - @Role.Name - - - - @* For Debug *@ - @* Current Permissions: @string.Join(", ", Role.Permissions) *@ - - @foreach (var group in _groups) - { - - - - - @group.Name (@group.Items.Count(x => x.Selected)/@group.Items.Count) - - - - - @foreach (var perm in group.Items) - { - - - - } - - - - } - - - - - Cancel - Save - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor deleted file mode 100644 index a36af169..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor +++ /dev/null @@ -1,103 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - Identifier Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - - - - - - Name - - - - - - - - - - - - - - - - - - - Personal - - - - - - - - - - - - - - - - - - - Localization - - - - - - - - - - - @foreach (var tz in TimeZoneInfo.GetSystemTimeZones()) - { - @tz.Id - @tz.DisplayName - } - - - - - - - - - - } - else - { -
- -
- } -
- - Cancel - Save - -
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor.cs deleted file mode 100644 index 611e7141..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ProfileDialog.razor.cs +++ /dev/null @@ -1,116 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class ProfileDialog -{ - private MudForm? _form; - private string? _firstName; - private string? _lastName; - private string? _displayName; - private DateTime? _birthDate; - private string? _gender; - private string? _bio; - private string? _language; - private string? _timeZone; - private string? _culture; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.GetMeAsync(); - } - else - { - result = await UAuthClient.Users.GetUserAsync(UserKey.Value); - } - - if (result.IsSuccess && result.Value is not null) - { - var p = result.Value; - - _firstName = p.FirstName; - _lastName = p.LastName; - _displayName = p.DisplayName; - - _gender = p.Gender; - _birthDate = p.BirthDate?.ToDateTime(TimeOnly.MinValue); - _bio = p.Bio; - - _language = p.Language; - _timeZone = p.TimeZone; - _culture = p.Culture; - } - _loaded = true; - } - - private async Task SaveAsync() - { - if (AuthState is null || AuthState.Identity is null) - { - Snackbar.Add("No AuthState found.", Severity.Error); - return; - } - - if (_form is not null) - { - await _form.ValidateAsync(); - if (!_form.IsValid) - return; - } - - var request = new UpdateProfileRequest - { - FirstName = _firstName, - LastName = _lastName, - DisplayName = _displayName, - BirthDate = _birthDate.HasValue ? DateOnly.FromDateTime(_birthDate.Value) : null, - Gender = _gender, - Bio = _bio, - Language = _language, - TimeZone = _timeZone, - Culture = _culture - }; - - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Users.UpdateMyProfileAsync(request); - } - else - { - result = await UAuthClient.Users.UpdateUserProfileAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Profile updated", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to update profile", Severity.Error); - } - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor deleted file mode 100644 index 8d4c90d3..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/ResetDialog.razor +++ /dev/null @@ -1,37 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Credentials.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Reset Credential - - - - - - This is a demonstration of how to implement a credential reset flow. - In a production application, you should use reset token or code in email, SMS etc. verification steps. - - - Reset request always returns ok even with not found users due to security reasons. - - - Request Reset - @if (_resetRequested) - { - Your reset code is on the server console. - Use Reset Code - } - - - - - Close - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor deleted file mode 100644 index bfcf9428..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor +++ /dev/null @@ -1,90 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@using CodeBeam.UltimateAuth.Core.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService - - - - - Role Management - Manage system roles - - - - @if (_loaded) - { - - - - - Roles - - - - - - - - - - - @GetPermissionCount(context.Item) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - } - else - { -
- -
- } -
- - - Close - -
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor.cs deleted file mode 100644 index f079d51a..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/RoleDialog.razor.cs +++ /dev/null @@ -1,176 +0,0 @@ -using CodeBeam.UltimateAuth.Authorization.Contracts; -using CodeBeam.UltimateAuth.Client; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class RoleDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _newRoleName; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new RoleQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Authorization.QueryRolesAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task CommittedItemChanges(RoleInfo role) - { - var req = new RenameRoleRequest - { - Id = role.Id, - Name = role.Name - }; - - var result = await UAuthClient.Authorization.RenameRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add("Role renamed", Severity.Success); - } - else - { - Snackbar.Add(result.ErrorText ?? "Rename failed", Severity.Error); - } - - await ReloadAsync(); - return DataGridEditFormAction.Close; - } - - private async Task CreateRole() - { - if (string.IsNullOrWhiteSpace(_newRoleName)) - { - Snackbar.Add("Role name required.", Severity.Warning); - return; - } - - var req = new CreateRoleRequest - { - Name = _newRoleName - }; - - var res = await UAuthClient.Authorization.CreateRoleAsync(req); - - if (res.IsSuccess) - { - Snackbar.Add("Role created.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(res.ErrorText ?? "Creation failed.", Severity.Error); - } - } - - private async Task DeleteRole(RoleId roleId) - { - var confirm = await DialogService.ShowMessageBoxAsync( - "Delete role", - "Are you sure?", - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, BackgroundClass = "uauth-blur-slight" }); - - if (confirm != true) - return; - - var req = new DeleteRoleRequest() { Id = roleId }; - var result = await UAuthClient.Authorization.DeleteRoleAsync(req); - - if (result.IsSuccess) - { - Snackbar.Add($"Role deleted, assignments removed from {result.Value?.RemovedAssignments.ToString() ?? "unknown"} users.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Deletion failed.", Severity.Error); - } - } - - private async Task EditPermissions(RoleInfo role) - { - var dialog = await DialogService.ShowAsync( - "Edit Permissions", - new DialogParameters - { - { nameof(PermissionDialog.Role), role } - }, - new DialogOptions - { - CloseButton = true, - MaxWidth = MaxWidth.Large, - FullWidth = true - }); - - var result = await dialog.Result; - await ReloadAsync(); - } - - private async Task ReloadAsync() - { - _loading = true; - await Task.Delay(300); - if (_grid is null) - return; - - await _grid.ReloadServerData(); - _loading = false; - } - - private int GetPermissionCount(RoleInfo role) - { - var expanded = PermissionExpander.Expand(role.Permissions, UAuthPermissionCatalog.GetAdminPermissions()); - return expanded.Count; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor deleted file mode 100644 index e5ee0c4d..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor +++ /dev/null @@ -1,226 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@inject IUAuthStateManager StateManager -@inject NavigationManager Nav - - - - Session Management - - @if (UserKey is null) - { - User: @AuthState?.Identity?.DisplayName - } - else - { - UserKey: @UserKey.Value - } - - - - @if (_loaded) - { - @if (_chainDetail is not null) - { - - - - Device Details - - - - @if (!_chainDetail.IsRevoked) - { - - Revoke Device - - } - - - - - - - Device Type - @_chainDetail.DeviceType - - - - Platform - @_chainDetail.Platform - - - - Operating System - @_chainDetail.OperatingSystem - - - - Browser - @_chainDetail.Browser - - - - Created - @_chainDetail.CreatedAt.ToLocalTime() - - - - Last Seen - @_chainDetail.LastSeenAt.ToLocalTime() - - - - State - - @_chainDetail.State - - - - - Active Session - @_chainDetail.ActiveSessionId - - - - Rotation Count - @_chainDetail.RotationCount - - - - Touch Count - @_chainDetail.TouchCount - - - - - - Session History - - - - Session Id - Created - Expires - Status - - - - @context.SessionId - @context.CreatedAt.ToLocalTime() - @context.ExpiresAt.ToLocalTime() - - @if (context.IsRevoked) - { - Revoked - } - else - { - Active - } - - - - - } - else - { - - Logout All Devices - @if (UserKey == null) - { - Logout Other Devices - } - Revoke All Devices - @if (UserKey == null) - { - Revoke Other Devices - } - - - - Sessions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.ChainId - - - - Created At - @context.Item.CreatedAt - - - - Touch Count - @context.Item.TouchCount - - - - Rotation Count - @context.Item.RotationCount - - - - - - - - - } - } - else - { -
- -
- } -
- - Cancel - -
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor.cs deleted file mode 100644 index b7b084d3..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/SessionDialog.razor.cs +++ /dev/null @@ -1,286 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class SessionDialog -{ - private MudDataGrid? _grid; - private bool _loading = false; - private bool _reloadQueued; - private SessionChainDetail? _chainDetail; - private bool _loaded; - - [CascadingParameter] - private IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey? UserKey { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - var result = await UAuthClient.Sessions.GetMyChainsAsync(); - if (result != null && result.IsSuccess && result.Value != null) - { - await ReloadAsync(); - } - StateHasChanged(); - } - } - - private async Task> LoadServerData(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new PageRequest - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - UAuthResult> res; - - if (UserKey is null) - { - res = await UAuthClient.Sessions.GetMyChainsAsync(req); - } - else - { - res = await UAuthClient.Sessions.GetUserChainsAsync(UserKey.Value, req); - } - - if (!res.IsSuccess || res.Value is null) - { - Snackbar.Add(res.Problem?.Title ?? "Failed", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - await Task.Delay(300); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task LogoutAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutAllMyDevicesAsync(); - } - else - { - result = await UAuthClient.Flows.LogoutAllUserDevicesAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task LogoutOthersAsync() - { - var result = await UAuthClient.Flows.LogoutMyOtherDevicesAsync(); - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of other devices.", Severity.Success); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout", Severity.Error); - } - } - - private async Task LogoutDeviceAsync(SessionChainId chainId) - { - LogoutDeviceRequest request = new() { ChainId = chainId }; - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Flows.LogoutMyDeviceAsync(request); - } - else - { - result = await UAuthClient.Flows.LogoutUserDeviceAsync(UserKey.Value, request); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of device.", Severity.Success); - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeAllAsync() - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeAllMyChainsAsync(); - } - else - { - result = await UAuthClient.Sessions.RevokeAllUserChainsAsync(UserKey.Value); - } - - if (result.IsSuccess) - { - Snackbar.Add("Logged out of all devices.", Severity.Success); - - if (UserKey is null) - Nav.NavigateTo("/login"); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeOthersAsync() - { - var result = await UAuthClient.Sessions.RevokeMyOtherChainsAsync(); - if (result.IsSuccess) - { - Snackbar.Add("Revoked all other devices.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task RevokeChainAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.RevokeMyChainAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.RevokeUserChainAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - Snackbar.Add("Device revoked successfully.", Severity.Success); - - if (result?.Value?.CurrentChain == true) - { - Nav.NavigateTo("/login"); - return; - } - await ReloadAsync(); - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to logout.", Severity.Error); - } - } - - private async Task ShowChainDetailsAsync(SessionChainId chainId) - { - UAuthResult result; - - if (UserKey is null) - { - result = await UAuthClient.Sessions.GetMyChainDetailAsync(chainId); - } - else - { - result = await UAuthClient.Sessions.GetUserChainDetailAsync(UserKey.Value, chainId); - } - - if (result.IsSuccess) - { - _chainDetail = result.Value; - } - else - { - Snackbar.Add(result?.ErrorText ?? "Failed to fetch chain details.", Severity.Error); - _chainDetail = null; - } - } - - private void ClearDetail() - { - _chainDetail = null; - } - - private void Cancel() => MudDialog.Cancel(); -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor.cs deleted file mode 100644 index 842af288..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserDetailDialog.razor.cs +++ /dev/null @@ -1,100 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UAuth.Sample.IntWasm.Client.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class UserDetailDialog -{ - private UserView? _user; - private AdminAssignableUserStatus _status; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - [Parameter] - public UserKey UserKey { get; set; } - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - var result = await UAuthClient.Users.GetUserAsync(UserKey); - - if (result.IsSuccess) - { - _user = result.Value; - _status = _user?.Status.ToAdminAssignableUserStatus() ?? AdminAssignableUserStatus.Unknown; - } - } - - private async Task OpenSessions() - { - await DialogService.ShowAsync("Session Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenProfile() - { - await DialogService.ShowAsync("Profile Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenIdentifiers() - { - await DialogService.ShowAsync("Identifier Management", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenCredentials() - { - await DialogService.ShowAsync("Credentials", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task OpenRoles() - { - await DialogService.ShowAsync("Roles", UAuthDialog.GetDialogParameters(AuthState, _user?.UserKey), UAuthDialog.GetDialogOptions()); - } - - private async Task ChangeStatusAsync() - { - if (_user is null) - return; - - ChangeUserStatusAdminRequest request = new() - { - NewStatus = _status, - }; - - var result = await UAuthClient.Users.ChangeUserStatusAsync(_user.UserKey, request); - - if (result.IsSuccess) - { - Snackbar.Add("User status updated", Severity.Success); - _user = _user with { Status = _status.ToUserStatus() }; - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed", Severity.Error); - } - } - - private Color GetStatusColor(UserStatus? status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor deleted file mode 100644 index 6e754848..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UserRoleDialog.razor +++ /dev/null @@ -1,49 +0,0 @@ -@using CodeBeam.UltimateAuth.Authorization.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - - User Roles - UserKey: @UserKey.Value - - - - - Assigned Roles - - @if (_roles.Count == 0) - { - No roles assigned - } - - - @foreach (var role in _roles) - { - @role - } - - - - - Add Role - - - - @foreach (var role in _allRoles) - { - @role.Name - } - - - Add - - - - - - Close - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor deleted file mode 100644 index 0eea8438..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor +++ /dev/null @@ -1,94 +0,0 @@ -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UAuth.Sample.IntWasm.Client.Common -@using CodeBeam.UltimateAuth.Users.Contracts -@inject IUAuthClient UAuthClient -@inject IDialogService DialogService -@inject ISnackbar Snackbar - - - - User Management - Browse, create and manage users - - - - @if (_loaded) - { - - - - - - - - - - - - - - Users - - New User - - - - - - - - - - - @context.Item.Status - - - - - - - - - - - - - - - - - - - - - Id - @context.Item.UserKey.Value - - - - Created At - @context.Item.CreatedAt - - - - - - - - - - } - else - { -
- -
- } -
- - - Close - -
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor.cs deleted file mode 100644 index cc24a17b..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Components/Dialogs/UsersDialog.razor.cs +++ /dev/null @@ -1,188 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UAuth.Sample.IntWasm.Client.Common; -using CodeBeam.UltimateAuth.Users.Contracts; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Components.Dialogs; - -public partial class UsersDialog -{ - private MudDataGrid? _grid; - private bool _loading; - private string? _search; - private bool _reloadQueued; - private UserStatus? _statusFilter; - private bool _loaded; - - [CascadingParameter] - IMudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] - public UAuthState AuthState { get; set; } = default!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - await base.OnAfterRenderAsync(firstRender); - - if (firstRender) - { - _loaded = true; - StateHasChanged(); - } - } - - private async Task> LoadUsers(GridState state, CancellationToken ct) - { - var sort = state.SortDefinitions?.FirstOrDefault(); - - var req = new UserQuery - { - PageNumber = state.Page + 1, - PageSize = state.PageSize, - Search = _search, - Status = _statusFilter, - SortBy = sort?.SortBy, - Descending = sort?.Descending ?? false - }; - - var res = await UAuthClient.Users.QueryAsync(req); - - if (!res.IsSuccess || res.Value == null) - { - Snackbar.Add(res.ErrorText ?? "Failed to load users.", Severity.Error); - - return new GridData - { - Items = Array.Empty(), - TotalItems = 0 - }; - } - - return new GridData - { - Items = res.Value.Items, - TotalItems = res.Value.TotalCount - }; - } - - private async Task ReloadAsync() - { - if (_loading) - { - _reloadQueued = true; - return; - } - - if (_grid is null) - return; - - _loading = true; - await InvokeAsync(StateHasChanged); - - try - { - await _grid.ReloadServerData(); - } - finally - { - _loading = false; - - if (_reloadQueued) - { - _reloadQueued = false; - await ReloadAsync(); - } - - await InvokeAsync(StateHasChanged); - } - } - - private async Task OnStatusChanged(UserStatus? status) - { - _statusFilter = status; - await ReloadAsync(); - } - - private async Task OpenUser(UserKey userKey) - { - var dialog = await DialogService.ShowAsync("User", UAuthDialog.GetDialogParameters(AuthState, userKey), UAuthDialog.GetDialogOptions()); - await dialog.Result; - await ReloadAsync(); - } - - private async Task OpenCreateUser() - { - var dialog = await DialogService.ShowAsync( - "Create User", - new DialogOptions - { - MaxWidth = MaxWidth.Small, - FullWidth = true, - CloseButton = true - }); - - var result = await dialog.Result; - - if (result?.Canceled == false) - await ReloadAsync(); - } - - private async Task DeleteUserAsync(UserSummary user) - { - var confirm = await DialogService.ShowMessageBoxAsync( - title: "Delete user", - markupMessage: (MarkupString)$""" - Are you sure you want to delete {user.DisplayName ?? user.UserName ?? user.PrimaryEmail ?? user.UserKey}? -

- This operation is intended for admin usage. - """, - yesText: "Delete", - cancelText: "Cancel", - options: new DialogOptions - { - MaxWidth = MaxWidth.Medium, - FullWidth = true, - BackgroundClass = "uauth-blur-slight" - }); - - if (confirm != true) - return; - - var req = new DeleteUserRequest - { - Mode = DeleteMode.Soft - }; - - var result = await UAuthClient.Users.DeleteUserAsync(UserKey.Parse(user.UserKey, null), req); - - if (result.IsSuccess) - { - Snackbar.Add("User deleted successfully.", Severity.Success); - await ReloadAsync(); - } - else - { - Snackbar.Add(result.ErrorText ?? "Failed to delete user.", Severity.Error); - } - } - - private static Color GetStatusColor(UserStatus status) - { - return status switch - { - UserStatus.Active => Color.Success, - UserStatus.SelfSuspended => Color.Warning, - UserStatus.Suspended => Color.Warning, - UserStatus.Disabled => Color.Error, - _ => Color.Default - }; - } - - private void Close() - { - MudDialog.Close(); - } -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor index d1498eb6..d7761a1b 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor @@ -1,68 +1,8 @@ @inherits LayoutComponentBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject NavigationManager Nav -@if (!RendererInfo.IsInteractive) -{ - - - -} - - - - - UltimateAuth - - Blazor WASM Sample - - - - - - - - - -
- - - @((state.Identity?.DisplayName ?? "?").Trim() is var n ? (n.Length >= 2 ? n[..2] : n[..1]) : "?") - - -
-
- - - @state.Identity?.DisplayName - @string.Join(", ", state.Claims.Roles) - - - - - - - - @if (state.Identity?.SessionState is not null && state.Identity.SessionState != SessionState.Active) - { - - - } - -
-
- - - - -
-
- - - @Body - -
+ + @Body +
diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor.cs deleted file mode 100644 index 1e788a96..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeBeam.UltimateAuth.Client; -using CodeBeam.UltimateAuth.Client.Errors; -using CodeBeam.UltimateAuth.Core.Contracts; -using CodeBeam.UltimateAuth.Core.Domain; -using CodeBeam.UltimateAuth.Core.Errors; -using CodeBeam.UAuth.Sample.IntWasm.Client.Infrastructure; -using Microsoft.AspNetCore.Components; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Layout; - -public partial class MainLayout -{ - [CascadingParameter] - public UAuthState UAuth { get; set; } = default!; - - [CascadingParameter] - public DarkModeManager DarkModeManager { get; set; } = default!; - - private async Task Refresh() - { - await UAuthClient.Flows.RefreshAsync(); - } - - private async Task Logout() - { - await UAuthClient.Flows.LogoutAsync(); - } - - private Color GetBadgeColor() - { - if (UAuth is null || !UAuth.IsAuthenticated) - return Color.Error; - - if (UAuth.IsStale) - return Color.Warning; - - var state = UAuth.Identity?.SessionState; - - if (state is null || state == SessionState.Active) - return Color.Success; - - if (state == SessionState.Invalid) - return Color.Error; - - return Color.Warning; - } - - private void HandleSignInClick() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true); - return; - } - - GoToLoginWithReturn(); - } - - private async Task Validate() - { - try - { - var result = await UAuthClient.Flows.ValidateAsync(); - - if (result.IsValid) - { - if (result.Snapshot?.Identity.UserStatus == UserStatus.SelfSuspended) - { - Snackbar.Add("Your account is suspended by you.", Severity.Warning); - return; - } - Snackbar.Add($"Session active • Tenant: {result.Snapshot?.Identity?.Tenant.Value} • User: {result.Snapshot?.Identity?.PrimaryUserName}", Severity.Success); - } - else - { - switch (result.State) - { - case SessionState.Expired: - Snackbar.Add("Session expired. Please sign in again.", Severity.Warning); - break; - - case SessionState.DeviceMismatch: - Snackbar.Add("Session invalid for this device.", Severity.Error); - break; - - default: - Snackbar.Add($"Session state: {result.State}", Severity.Error); - break; - } - } - } - catch (UAuthTransportException) - { - Snackbar.Add("Network error.", Severity.Error); - } - catch (UAuthProtocolException) - { - Snackbar.Add("Invalid response.", Severity.Error); - } - catch (UAuthException ex) - { - Snackbar.Add($"UAuth error: {ex.Message}", Severity.Error); - } - catch (Exception ex) - { - Snackbar.Add($"Unexpected error: {ex.Message}", Severity.Error); - } - } - - private void GoToLoginWithReturn() - { - var uri = Nav.ToAbsoluteUri(Nav.Uri); - - if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase)) - { - Nav.NavigateTo("/login", replace: true); - return; - } - - var current = Nav.ToBaseRelativePath(uri.ToString()); - if (string.IsNullOrWhiteSpace(current)) - current = "home"; - - var returnUrl = Uri.EscapeDataString("/" + current.TrimStart('/')); - Nav.NavigateTo($"/login?returnUrl={returnUrl}", replace: true); - } -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/AuthorizedTestPage.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/AuthorizedTestPage.razor index 962555ed..0a953043 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/AuthorizedTestPage.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/AuthorizedTestPage.razor @@ -1,27 +1,4 @@ @page "/authorized-test" @attribute [UAuthAuthorize] -@inherits UAuthPageBase - - - - - - Everything is Ok - - - If you see this section, it means you succesfully logged in. - - - - Go Home Page - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - \ No newline at end of file + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor index 2503b3af..945a4332 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Home.razor @@ -1,454 +1,4 @@ @page "/home" @attribute [UAuthAuthorize] -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject UAuthClientDiagnostics Diagnostics -@inject AuthenticationStateProvider AuthStateProvider -@inject ISnackbar Snackbar -@inject IDialogService DialogService -@using System.Security.Claims -@using CodeBeam.UltimateAuth.Client.Diagnostics -@using CodeBeam.UltimateAuth.Core.Contracts -@using CodeBeam.UltimateAuth.Core.Defaults -@using CodeBeam.UAuth.Sample.IntWasm.Client.Components.Custom -@using Microsoft.AspNetCore.Authorization - -@if (AuthState?.Identity?.UserStatus == UserStatus.SelfSuspended) -{ - - - - Your account is suspended. Please active it before continue. - - - - Set Active - Logout - - - - return; -} - -@if (AuthState?.Identity?.UserStatus == UserStatus.Suspended) -{ - - - - Your account is suspended. Please contact with administrator. - - - - Logout - - - - return; -} - - - - - - - - - - - Session - - - - - - - Validate - - - - - - Manual Refresh - - - - - - Logout - - - - - - Account - - - - - Manage Sessions - - - - Manage Profile - - - - Manage Identifiers - - - - Manage Credentials - - - - Suspend | Delete Account - - - - Admin - - - - - - - - - @if (_showAdminPreview) - { - - Admin operations are shown for preview. Sign in as an Admin to execute them. - - } - - @if (AuthState?.IsInRole("Admin") == true || _showAdminPreview) - { - - - - @* *@ - @* *@ - User Management - @* *@ - - - - - - @* *@ - Role Management - @* *@ - - - - } - - - Resource Api - - - - - Manage Resource - - - - - - - - - - - - @((AuthState?.Identity?.DisplayName ?? "?").Substring(0, Math.Min(2, (AuthState?.Identity?.DisplayName ?? "?").Length))) - - - - @AuthState?.Identity?.DisplayName - - @foreach (var role in AuthState?.Claims?.Roles ?? Enumerable.Empty()) - { - - @role - - } - - - - - - - - - - @if (_selectedAuthState == "UAuthState") - { - - -
- - - Tenant - - @AuthState?.Identity?.Tenant.Value -
- -
- - -
- - - User Id - - @AuthState?.Identity?.UserKey.Value -
-
- - -
- - - Authenticated - - @(AuthState?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - Session State - - @AuthState?.Identity?.SessionState?.ToDescriptionString() -
-
- - -
- - - Username - - @AuthState?.Identity?.PrimaryUserName -
-
- - -
- - - Display Name - - @AuthState?.Identity?.DisplayName -
-
- - - - - - - Email - - @AuthState?.Identity?.PrimaryEmail - - - - - - Phone - - @AuthState?.Identity?.PrimaryPhone - - - - - - - - Authenticated At - - @* TODO: Add IUAuthDateTimeFormatter *@ - @FormatLocalTime(AuthState?.Identity?.AuthenticatedAt) - - - - - - Last Validated At - - @* TODO: Validation call should update last validated at *@ - @FormatLocalTime(AuthState?.LastValidatedAt) - -
- } - else if (_selectedAuthState == "AspNetCoreState") - { - - -
- - - Authenticated - - @(_aspNetCoreState?.Identity?.IsAuthenticated == true ? "Yes" : "No") -
-
- - -
- - - User Id - - @_aspNetCoreState?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value -
-
- - -
- - - Username - - @_aspNetCoreState?.Identity?.Name -
-
- - -
- - - Authentication Type - - @_aspNetCoreState?.Identity?.AuthenticationType -
-
-
- } -
-
-
- - - - - - @GetHealthText() - - - Lifecycle - - - - - - Started - @Diagnostics.StartCount - - @if (Diagnostics.StartedAt is not null) - { - - - - @FormatRelative(Diagnostics.StartedAt) - - - } - - - - - Stopped - @Diagnostics.StopCount - - - - - - Terminated - @Diagnostics.TerminatedCount - - @if (Diagnostics.TerminatedAt is not null) - { - - - - - @FormatRelative(Diagnostics.TerminatedAt) - - - - } - - - - - - Refresh Metrics - - - - - - - Total Attempts - @Diagnostics.RefreshAttemptCount - - - - - - - Success - - @Diagnostics.RefreshSuccessCount - - - - - - Automatic - @Diagnostics.AutomaticRefreshCount - - - - - - Manual - @Diagnostics.ManualRefreshCount - - - - - - Touched/Rotated - @Diagnostics.RefreshTouchedCount / @Diagnostics.RefreshRotatedCount - - - - - - No-Op - @Diagnostics.RefreshNoOpCount - - - - - - Reauth Required - @Diagnostics.RefreshReauthRequiredCount - - - - - - - -
-
-
+ \ No newline at end of file diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor index 1e4a9016..a02d91bf 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor @@ -1,4 +1,3 @@ @page "/" -@inject NavigationManager Nav -@inject AuthenticationStateProvider AuthProvider + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor.cs deleted file mode 100644 index ac24e527..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/LandingPage.razor.cs +++ /dev/null @@ -1,17 +0,0 @@ -using CodeBeam.UltimateAuth.Core.Defaults; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; - -public partial class LandingPage -{ - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (!firstRender) - return; - - var state = await AuthProvider.GetAuthenticationStateAsync(); - var isAuthenticated = state.User.Identity?.IsAuthenticated == true; - - Nav.NavigateTo(isAuthenticated ? "/home" : $"{UAuthConstants.Routes.LoginRedirect}?fresh=true"); - } -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor index 43e409a7..12aa98c8 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Login.razor @@ -1,135 +1,4 @@ @page "/login" -@using CodeBeam.UltimateAuth.Client.Runtime @attribute [UAuthLoginPage] -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor deleted file mode 100644 index d8eb7138..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/NotAuthorized.razor +++ /dev/null @@ -1,27 +0,0 @@ -@inject NavigationManager Nav - - - - - - - Access Denied - - - You don’t have permission to view this page. - If you think this is a mistake, sign in with a different account or request access. - - - - Sign In - Go Back - - - - - - UltimateAuth protects this resource based on your session and permissions. - - - - diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor index 41c7e05b..745143b0 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/Register.razor @@ -1,61 +1,3 @@ @page "/register" -@using CodeBeam.UltimateAuth.Client.Runtime -@inherits UAuthPageBase -@implements IDisposable -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar -@inject IUAuthClientProductInfoProvider ClientProductInfoProvider -@inject IDeviceIdProvider DeviceIdProvider -@inject IDialogService DialogService - - - - - - - - - - - - - - + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor index 2623395b..f2c1a536 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor @@ -1,18 +1,3 @@ @page "/reset" -@inherits UAuthPageBase -@inject IUAuthClient UAuthClient -@inject ISnackbar Snackbar - - - - - - - - - Change Password - - - - \ No newline at end of file + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor.cs deleted file mode 100644 index 4e8847fe..00000000 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Pages/ResetCredential.razor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CodeBeam.UltimateAuth.Credentials.Contracts; -using MudBlazor; - -namespace CodeBeam.UAuth.Sample.IntWasm.Client.Pages; - -public partial class ResetCredential -{ - private MudForm _form = null!; - private string? _code; - private string? _newPassword; - private string? _newPasswordCheck; - - private async Task ResetPasswordAsync() - { - await _form.ValidateAsync(); - if (!_form.IsValid) - { - Snackbar.Add("Please fix the validation errors.", Severity.Error); - return; - } - - if (_newPassword != _newPasswordCheck) - { - Snackbar.Add("Passwords do not match.", Severity.Error); - return; - } - - if (string.IsNullOrEmpty(_code) || string.IsNullOrEmpty(_newPassword) || string.IsNullOrEmpty(Identifier)) - { - Snackbar.Add("Missing required information. Please ensure you have a valid reset code and new password.", Severity.Error); - return; - } - - var request = new CompleteResetCredentialRequest - { - ResetToken = _code, - NewSecret = _newPassword, - Identifier = Identifier // Coming from UAuthFlowPageBase automatically if begin reset is successful - }; - - var result = await UAuthClient.Credentials.CompleteResetAsync(request); - - if (result.IsSuccess) - { - Snackbar.Add("Credential reset successfully. Please log in with your new password.", Severity.Success); - Navigation.NavigateTo("/login"); - } - else - { - Snackbar.Add(result.Problem?.Detail ?? result.Problem?.Title ?? "Failed to reset credential. Please try again.", Severity.Error); - } - } - - private string PasswordMatch(string arg) => _newPassword != arg ? "Passwords don't match" : string.Empty; -} diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Program.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Program.cs index adb7d26a..415c3f67 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Program.cs +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Program.cs @@ -1,7 +1,7 @@ -using CodeBeam.UAuth.Sample.IntWasm.Client.Infrastructure; -using CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor.Services; using MudExtensions.Services; @@ -13,13 +13,13 @@ }); builder.Services.AddMudExtensions(); builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); -builder.Services.AddHttpClient("resourceApi", client => +builder.Services.AddHttpClient(client => { - client.BaseAddress = new Uri("https://localhost:6122"); + client.BaseAddress = new Uri("https://localhost:6122"); // EFCore Resource API URL }); builder.Services.AddUltimateAuthClientBlazor(o => diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Routes.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Routes.razor index e102e257..312137a2 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Routes.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Routes.razor @@ -1,73 +1,2 @@ -@using CodeBeam.UAuth.Sample.IntWasm.Client.Pages -@using CodeBeam.UAuth.Sample.IntWasm.Client.Infrastructure -@inject ISnackbar Snackbar -@inject DarkModeManager DarkModeManager - - - - - - - - - - - - - - - - @* Advanced: you can fully control routing by providing your own Router *@ - @* - - - - - - - - - - - - - - - - *@ - - -@code { - private async Task HandleReauth() - { - Snackbar.Add("Reauthentication required. Please log in again.", Severity.Warning); - } - - #region DarkMode - - protected override void OnInitialized() - { - DarkModeManager.Changed += OnThemeChanged; - } - - private void OnThemeChanged() - { - InvokeAsync(StateHasChanged); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - await DarkModeManager.InitializeAsync(); - StateHasChanged(); - } - } - - public void Dispose() - { - DarkModeManager.Changed -= OnThemeChanged; - } - - #endregion -} + + \ No newline at end of file diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/_Imports.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/_Imports.razor index 6fb3b530..819b9c9e 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/_Imports.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/_Imports.razor @@ -15,5 +15,9 @@ @using CodeBeam.UltimateAuth.Client @using CodeBeam.UltimateAuth.Client.Blazor +@using CodeBeam.UltimateAuth.Sample.Shared.Components +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Page +@using CodeBeam.UltimateAuth.Sample.Shared.Components.Layout + @using MudBlazor @using MudExtensions diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.csproj b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.csproj index e03668c9..2154aec8 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.csproj +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.csproj @@ -11,7 +11,7 @@ - + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Components/App.razor b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Components/App.razor index 6ba144f0..794bd19e 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Components/App.razor +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Components/App.razor @@ -9,6 +9,7 @@ + diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Program.cs b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Program.cs index 7790e14a..10c609ad 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Program.cs +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/Program.cs @@ -1,23 +1,30 @@ -using CodeBeam.UAuth.Sample.IntWasm.Client.Infrastructure; -using CodeBeam.UAuth.Sample.IntWasm.Client.ResourceApi; using CodeBeam.UAuth.Sample.IntWasm.Components; using CodeBeam.UltimateAuth.Client.AspNetCore; using CodeBeam.UltimateAuth.Client.Blazor; using CodeBeam.UltimateAuth.Client.Blazor.Extensions; using CodeBeam.UltimateAuth.Core.Domain; +using CodeBeam.UltimateAuth.Sample.Shared.Infrastructure; +using CodeBeam.UltimateAuth.Sample.Shared.ResourceApi; using MudBlazor.Services; using MudExtensions.Services; var builder = WebApplication.CreateBuilder(args); +# region Essentials & UI & MudBlazor - Extensions + builder.Services.AddRazorComponents() .AddInteractiveWebAssemblyComponents(); builder.Services.AddMudServices(o => { o.SnackbarConfiguration.PreventDuplicates = false; }); + builder.Services.AddMudExtensions(); +builder.Services.AddScoped(); + +# endregion + builder.Services.AddUltimateAuthClientBlazor(o => { o.Endpoints.BasePath = "https://localhost:6112/auth"; // UAuthHub EFCore URL @@ -26,18 +33,15 @@ o.Pkce.ReturnUrl = "https://localhost:6132/home"; // This application domain + path }); -builder.Services.AddScoped(); - builder.Services.AddUltimateAuthAspNetCoreCompatibility(); + // If you want to use the UltimateAuthClientBlazor without the AspNetCore compatibility layer, you can register the services like this instead: -// It gives full AspNetCore compatibility but affects performance significantly. +// It gives full AspNetCore compatibility but decreases performance significantly. //builder.Services.AddUltimateAuthResourceApi(o => o.UAuthHubBaseUrl = "https://localhost:6112/auth"); -builder.Services.AddScoped(); - -builder.Services.AddHttpClient("resourceApi", client => +builder.Services.AddHttpClient(client => { - client.BaseAddress = new Uri("https://localhost:6122"); // Resource API URL + client.BaseAddress = new Uri("https://localhost:6122"); // EFCore Resource API URL }); var app = builder.Build(); diff --git a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/wwwroot/app.css b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/wwwroot/app.css index 5b69be65..91f03d8f 100644 --- a/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/wwwroot/app.css +++ b/samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm/wwwroot/app.css @@ -112,95 +112,3 @@ code { .form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder { text-align: start; } - -.uauth-stack { - min-height: 60vh; - max-height: calc(100vh - var(--mud-appbar-height)); - width: 30vw; - min-width: 300px; -} - -.uauth-menu-popover { - width: 300px; -} - -.uauth-login-paper { - min-height: 70vh; -} - - .uauth-login-paper.mud-theme-primary { - background: linear-gradient(145deg, var(--mud-palette-primary), rgba(0, 0, 0, 0.85) ); - color: white; - } - -.uauth-brand-glow { - filter: drop-shadow(0 0 25px rgba(255,255,255,0.15)); -} - -.uauth-logo-slide { - animation: uauth-logo-float 30s ease-in-out infinite; -} - -.uauth-text-transform-none .mud-button { - text-transform: none; -} - -.uauth-dialog { - height: 68vh; - max-height: 68vh; - overflow: auto; -} - -.text-secondary { - color: var(--mud-palette-text-secondary); -} - -.uauth-blur { - backdrop-filter: blur(10px); -} - -.uauth-blur-slight { - backdrop-filter: blur(4px); -} - -@keyframes uauth-logo-float { - 0% { - transform: translateY(0) rotateY(0); - } - - 10% { - transform: translateY(0) rotateY(0); - } - - 15% { - transform: translateY(200px) rotateY(360deg); - } - - 35% { - transform: translateY(200px) rotateY(360deg); - } - - 40% { - transform: translateY(200px) rotateY(720deg); - } - - 60% { - transform: translateY(200px) rotateY(720deg); - } - - 65% { - transform: translateY(0) rotateY(360deg); - } - - 85% { - transform: translateY(0) rotateY(360deg); - } - - 90% { - transform: translateY(0) rotateY(0); - } - - 100% { - transform: translateY(0) rotateY(0); - } -} diff --git a/samples/resource-api/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore.csproj b/samples/resource-api/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore.csproj index 20471edc..cde66c01 100644 --- a/samples/resource-api/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore.csproj +++ b/samples/resource-api/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore/CodeBeam.UltimateAuth.Sample.ResourceApi.EfCore.csproj @@ -4,6 +4,7 @@ net10.0 enable enable + false diff --git a/src/client/CodeBeam.UltimateAuth.Client.AspNetCore/ServiceCollectionExtensions.cs b/src/client/CodeBeam.UltimateAuth.Client.AspNetCore/ServiceCollectionExtensions.cs index b546b9d5..88381382 100644 --- a/src/client/CodeBeam.UltimateAuth.Client.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/client/CodeBeam.UltimateAuth.Client.AspNetCore/ServiceCollectionExtensions.cs @@ -5,12 +5,9 @@ namespace CodeBeam.UltimateAuth.Client.AspNetCore; public static class UAuthAspNetCoreExtensions { - public static IServiceCollection AddUltimateAuthAspNetCoreCompatibility( - this IServiceCollection services) + public static IServiceCollection AddUltimateAuthAspNetCoreCompatibility(this IServiceCollection services) { - services.AddAuthentication("UAuth.Noop") - .AddScheme("UAuth.Noop", _ => { }); - + services.AddAuthentication("UAuth.Noop").AddScheme("UAuth.Noop", _ => { }); services.AddAuthorization(); return services;