Skip to content

Commit 763c4ea

Browse files
authored
Preparation of First Release (Part 5/7) (#13)
* Preparation of First Release (Part 5/7) * Add Complete Refresh Flow Especially For PureOpaque and Hybrid Auth Mode * Add PKCE for Login Flow * Add PKCE form login & Failed Behavior * PKCE Polish & Cleanup * Fix SessionId Cookie MaxAge on Hybrid Auth Mode * Add DeviceId Support & Big Refactoring * Minor Fixes * Fix Tests
1 parent 286c742 commit 763c4ea

File tree

297 files changed

+5731
-3133
lines changed

Some content is hidden

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

297 files changed

+5731
-3133
lines changed

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="9.0.0-preview.1" />
12+
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="9.0.0-preview.3" />
1313
<PackageReference Include="MudBlazor" Version="9.0.0-preview.1" />
1414
</ItemGroup>
1515

1616
<ItemGroup>
17+
<ProjectReference Include="..\..\..\src\CodeBeam.UltimateAuth.Client\CodeBeam.UltimateAuth.Client.csproj" />
1718
<ProjectReference Include="..\..\..\src\CodeBeam.UltimateAuth.Core\CodeBeam.UltimateAuth.Core.csproj" />
1819
<ProjectReference Include="..\..\..\src\CodeBeam.UltimateAuth.Server\CodeBeam.UltimateAuth.Server.csproj" />
1920
<ProjectReference Include="..\..\..\src\credentials\CodeBeam.UltimateAuth.Credentials.InMemory\CodeBeam.UltimateAuth.Credentials.InMemory.csproj" />

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
@inherits LayoutComponentBase
1+
@using CodeBeam.UltimateAuth.Core.Abstractions
2+
@using CodeBeam.UltimateAuth.Server.Infrastructure
3+
@inherits LayoutComponentBase
4+
5+
<UAuthClientProvider />
6+
<MudThemeProvider />
7+
<MudPopoverProvider />
8+
<MudDialogProvider />
9+
<MudSnackbarProvider />
210

311
@Body
412

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Layout
2+
{
3+
public partial class MainLayout
4+
{
5+
6+
}
7+
}

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor.css

Lines changed: 0 additions & 98 deletions
This file was deleted.

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Counter.razor

Lines changed: 0 additions & 18 deletions
This file was deleted.

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Pages/Home.razor

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,68 @@
11
@page "/"
2+
@page "/login"
3+
@using CodeBeam.UltimateAuth.Client
4+
@using CodeBeam.UltimateAuth.Client.Authentication
5+
@using CodeBeam.UltimateAuth.Client.Diagnostics
6+
@using CodeBeam.UltimateAuth.Client.Utilities
7+
@using CodeBeam.UltimateAuth.Core.Abstractions
8+
@using CodeBeam.UltimateAuth.Core.Contracts
9+
@using CodeBeam.UltimateAuth.Core.Domain
10+
@using CodeBeam.UltimateAuth.Core.Runtime
11+
@using CodeBeam.UltimateAuth.Server.Abstractions
12+
@using CodeBeam.UltimateAuth.Server.Cookies
13+
@using CodeBeam.UltimateAuth.Server.Infrastructure
14+
@using CodeBeam.UltimateAuth.Server.Services
15+
@using CodeBeam.UltimateAuth.Server.Stores
16+
@inject IUAuthStateManager StateManager
17+
@inject IHubFlowReader HubFlowReader
18+
@inject IHubCredentialResolver HubCredentialResolver
19+
@inject IAuthStore AuthStore
20+
@inject IBrowserStorage BrowserStorage
21+
@inject IUAuthFlowService<UserKey> Flow
22+
@inject ISnackbar Snackbar
23+
@inject IFlowCredentialResolver CredentialResolver
24+
@inject IUAuthClient UAuthClient
25+
@inject NavigationManager Nav
26+
@inject IUAuthProductInfoProvider ProductInfo
27+
@inject AuthenticationStateProvider AuthStateProvider
28+
@inject UAuthClientDiagnostics Diagnostics
229

3-
<PageTitle>Home</PageTitle>
430

5-
<h1>Hello, world!</h1>
31+
<div class="uauth-page d-flex align-center justify-center">
32+
<MudStack Class="uauth-stack">
33+
@if (_state == null || !_state.IsActive)
34+
{
35+
<MudText>
36+
This page cannot be accessed directly.
37+
UAuthHub login flows can only be initiated by an authorized client application.
38+
</MudText>
39+
return;
40+
}
41+
<UALoginForm Identifier="@_username" Secret="@_password" LoginType="UAuthLoginType.Pkce">
42+
<MudStack>
43+
<MudText Typo="Typo.h4">Welcome to UltimateAuth!</MudText>
44+
<MudTextField @bind-Value="@_username" Variant="Variant.Outlined" Label="Username" Immediate="true" HelperText="Default: Admin" />
45+
<MudPasswordField @bind-Value="@_password" Variant="Variant.Outlined" Label="Password" Immediate="true" HelperText="Default: Password!" />
46+
<MudButton Variant="Variant.Filled" Color="Color.Primary" ButtonType="ButtonType.Submit">Login</MudButton>
47+
</MudStack>
48+
</UALoginForm>
49+
50+
<MudStack Class="mud-width-full">
51+
<MudButton Variant="Variant.Filled" Color="Color.Info" OnClick="ProgrammaticPkceLogin">Programmatic Pkce Login</MudButton>
52+
</MudStack>
53+
54+
<MudStack Spacing="0">
55+
<MudText><b>@ProductInfo.Get().ProductName</b> v @ProductInfo.Get().Version</MudText>
56+
<MudText>Client Profile: @ProductInfo.Get().ClientProfile.ToString()</MudText>
57+
</MudStack>
58+
59+
<MudStack Spacing="0">
60+
<MudText>Hub SessionId: @_state?.HubSessionId</MudText>
61+
<MudText>Client Profile: @_state?.ClientProfile</MudText>
62+
<MudText>Return Url: @_state?.ReturnUrl</MudText>
63+
<MudText>Flow Type: @_state?.FlowType</MudText>
64+
<MudText>IsActive: @_state?.IsActive</MudText>
65+
</MudStack>
66+
</MudStack>
67+
</div>
668

7-
Welcome to your new app.
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using CodeBeam.UltimateAuth.Client.Contracts;
2+
using CodeBeam.UltimateAuth.Client.Utilities;
3+
using CodeBeam.UltimateAuth.Core.Contracts;
4+
using CodeBeam.UltimateAuth.Core.Domain;
5+
using CodeBeam.UltimateAuth.Server.Stores;
6+
using Microsoft.AspNetCore.Components;
7+
using Microsoft.AspNetCore.WebUtilities;
8+
using MudBlazor;
9+
10+
namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Pages
11+
{
12+
public partial class Home
13+
{
14+
[SupplyParameterFromQuery(Name = "hub")]
15+
public string? HubKey { get; set; }
16+
17+
private string? _username;
18+
private string? _password;
19+
20+
private HubFlowState? _state;
21+
22+
protected override async Task OnParametersSetAsync()
23+
{
24+
if (string.IsNullOrWhiteSpace(HubKey))
25+
{
26+
_state = null;
27+
return;
28+
}
29+
30+
_state = await HubFlowReader.GetStateAsync(new HubSessionId(HubKey));
31+
}
32+
33+
protected override async Task OnAfterRenderAsync(bool firstRender)
34+
{
35+
if (!firstRender)
36+
return;
37+
38+
var currentError = await BrowserStorage.GetAsync(StorageScope.Session, "uauth:last_error");
39+
40+
if (!string.IsNullOrWhiteSpace(currentError))
41+
{
42+
Snackbar.Add(ResolveErrorMessage(currentError), Severity.Error);
43+
await BrowserStorage.RemoveAsync(StorageScope.Session, "uauth:last_error");
44+
}
45+
46+
var uri = Nav.ToAbsoluteUri(Nav.Uri);
47+
var query = QueryHelpers.ParseQuery(uri.Query);
48+
49+
if (query.TryGetValue("__uauth_error", out var error))
50+
{
51+
await BrowserStorage.SetAsync(StorageScope.Session, "uauth:last_error", error.ToString());
52+
}
53+
54+
if (string.IsNullOrWhiteSpace(HubKey))
55+
{
56+
return;
57+
}
58+
59+
if (_state is null || !_state.Exists)
60+
return;
61+
62+
if (_state?.IsActive != true)
63+
{
64+
await StartNewPkceAsync();
65+
return;
66+
}
67+
}
68+
69+
// For testing & debugging
70+
private async Task ProgrammaticPkceLogin()
71+
{
72+
var hub = _state;
73+
74+
if (hub is null)
75+
return;
76+
77+
var credentials = await HubCredentialResolver.ResolveAsync(new HubSessionId(HubKey));
78+
79+
var request = new PkceLoginRequest
80+
{
81+
Identifier = "Admin",
82+
Secret = "Password!",
83+
AuthorizationCode = credentials?.AuthorizationCode ?? string.Empty,
84+
CodeVerifier = credentials?.CodeVerifier ?? string.Empty,
85+
ReturnUrl = _state?.ReturnUrl ?? string.Empty
86+
};
87+
await UAuthClient.CompletePkceLoginAsync(request);
88+
}
89+
90+
private async Task StartNewPkceAsync()
91+
{
92+
var returnUrl = await ResolveReturnUrlAsync();
93+
await UAuthClient.BeginPkceAsync(returnUrl);
94+
}
95+
96+
private async Task<string> ResolveReturnUrlAsync()
97+
{
98+
var fromContext = _state?.ReturnUrl;
99+
if (!string.IsNullOrWhiteSpace(fromContext))
100+
return fromContext;
101+
102+
var uri = Nav.ToAbsoluteUri(Nav.Uri);
103+
var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
104+
105+
if (query.TryGetValue("return_url", out var ru) && !string.IsNullOrWhiteSpace(ru))
106+
return ru!;
107+
108+
if (query.TryGetValue("hub", out var hubKey) && !string.IsNullOrWhiteSpace(hubKey))
109+
{
110+
var artifact = await AuthStore.GetAsync(new AuthArtifactKey(hubKey!));
111+
if (artifact is HubFlowArtifact flow && !string.IsNullOrWhiteSpace(flow.ReturnUrl))
112+
return flow.ReturnUrl!;
113+
}
114+
115+
// Config default (recommend adding to options)
116+
//if (!string.IsNullOrWhiteSpace(_options.Login.DefaultReturnUrl))
117+
// return _options.Login.DefaultReturnUrl!;
118+
119+
return Nav.Uri;
120+
}
121+
122+
private string ResolveErrorMessage(string? errorKey)
123+
{
124+
if (errorKey == "invalid")
125+
{
126+
return "Login failed.";
127+
}
128+
129+
return "Failed attempt.";
130+
}
131+
132+
}
133+
}
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
2-
<Found Context="routeData">
3-
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
4-
<FocusOnNavigate RouteData="routeData" Selector="h1" />
5-
</Found>
6-
</Router>
1+
<CascadingAuthenticationState>
2+
<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
3+
<Found Context="routeData">
4+
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
5+
<FocusOnNavigate RouteData="routeData" Selector="h1" />
6+
</Found>
7+
</Router>
8+
</CascadingAuthenticationState>

samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/_Imports.razor

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
@using Microsoft.AspNetCore.Components.Web
66
@using static Microsoft.AspNetCore.Components.Web.RenderMode
77
@using Microsoft.AspNetCore.Components.Web.Virtualization
8+
@using Microsoft.AspNetCore.Components.Authorization
89
@using Microsoft.JSInterop
9-
@using UltimateAuth.Sample.UAuthHub
10-
@using UltimateAuth.Sample.UAuthHub.Components
11-
@using UltimateAuth.Sample.UAuthHub.Components.Layout
10+
@using CodeBeam.UltimateAuth.Sample.UAuthHub
11+
@using CodeBeam.UltimateAuth.Sample.UAuthHub.Components
12+
@using CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Layout
13+
@using CodeBeam.UltimateAuth.Client
14+
15+
@using MudBlazor
16+
@using MudExtensions

0 commit comments

Comments
 (0)