Skip to content

Commit 04b73ca

Browse files
committed
Add PKCE for Login Flow
1 parent 5bd4ce8 commit 04b73ca

File tree

74 files changed

+1718
-277
lines changed

Some content is hidden

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

74 files changed

+1718
-277
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+
@inherits LayoutComponentBase
3+
@inject IUAuthHubContextInitializer HubContextInitializer
4+
5+
<UAuthClientProvider />
6+
<MudThemeProvider />
7+
<MudPopoverProvider />
8+
<MudDialogProvider />
9+
<MudSnackbarProvider />
210

311
@Body
412

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Layout
2+
{
3+
public partial class MainLayout
4+
{
5+
protected override async Task OnAfterRenderAsync(bool firstRender)
6+
{
7+
if (firstRender)
8+
{
9+
await HubContextInitializer.EnsureInitializedAsync();
10+
}
11+
}
12+
}
13+
}

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: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,58 @@
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.Core.Abstractions
7+
@using CodeBeam.UltimateAuth.Core.Domain
8+
@using CodeBeam.UltimateAuth.Core.Runtime
9+
@using CodeBeam.UltimateAuth.Server.Abstractions
10+
@using CodeBeam.UltimateAuth.Server.Cookies
11+
@using CodeBeam.UltimateAuth.Server.Infrastructure
12+
@using CodeBeam.UltimateAuth.Server.Services
13+
@using CodeBeam.UltimateAuth.Server.Stores
14+
@inject IUAuthStateManager StateManager
15+
@inject IAuthStore AuthStore
16+
@inject UAuthHubContextAccessor HubContextAccessor
17+
@inject IUAuthFlowService<UserId> Flow
18+
@inject ISnackbar Snackbar
19+
@inject ISessionQueryService<UserId> SessionQuery
20+
@inject IFlowCredentialResolver CredentialResolver
21+
@inject IUAuthClient UAuthClient
22+
@inject NavigationManager Nav
23+
@inject IUAuthProductInfoProvider ProductInfo
24+
@inject AuthenticationStateProvider AuthStateProvider
25+
@inject UAuthClientDiagnostics Diagnostics
226

3-
<PageTitle>Home</PageTitle>
427

5-
<h1>Hello, world!</h1>
28+
<div class="uauth-page d-flex align-center justify-center">
29+
<MudStack Class="uauth-stack">
30+
<UALoginForm @ref="_form" Identifier="@_username" Secret="@_password">
31+
<MudStack>
32+
<MudText Typo="Typo.h4">Welcome to UltimateAuth!</MudText>
33+
<MudTextField @bind-Value="@_username" Variant="Variant.Outlined" Label="Username" Immediate="true" HelperText="Default: Admin" />
34+
<MudPasswordField @bind-Value="@_password" Variant="Variant.Outlined" Label="Password" Immediate="true" HelperText="Default: Password!" />
35+
<MudButton Variant="Variant.Filled" Color="Color.Primary" ButtonType="ButtonType.Submit">Login</MudButton>
36+
</MudStack>
37+
</UALoginForm>
38+
39+
<MudStack Class="mud-width-full">
40+
<MudButton Variant="Variant.Filled" Color="Color.Info" OnClick="ProgrammaticPkceLogin">Programmatic Pkce Login</MudButton>
41+
</MudStack>
42+
43+
<MudStack Spacing="0">
44+
<MudText><b>@ProductInfo.Get().ProductName</b> v @ProductInfo.Get().Version</MudText>
45+
<MudText>Client Profile: @ProductInfo.Get().ClientProfile.ToString()</MudText>
46+
</MudStack>
47+
48+
<MudStack Spacing="0">
49+
<MudText>Hub SessionId: @HubContextAccessor?.Current?.HubSessionId</MudText>
50+
<MudText>Client Profile: @HubContextAccessor?.Current?.ClientProfile</MudText>
51+
<MudText>Return Url: @HubContextAccessor?.Current?.ReturnUrl</MudText>
52+
<MudText>Flow Type: @HubContextAccessor?.Current?.FlowType</MudText>
53+
<MudText>Created At: @HubContextAccessor?.Current?.CreatedAt</MudText>
54+
</MudStack>
55+
</MudStack>
56+
57+
</div>
658

7-
Welcome to your new app.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using CodeBeam.UltimateAuth.Client;
2+
using CodeBeam.UltimateAuth.Core.Contracts;
3+
using CodeBeam.UltimateAuth.Core.Domain;
4+
using CodeBeam.UltimateAuth.Server.Stores;
5+
using Microsoft.AspNetCore.Components;
6+
using Microsoft.AspNetCore.Components.Authorization;
7+
using MudBlazor;
8+
9+
namespace CodeBeam.UltimateAuth.Sample.UAuthHub.Components.Pages
10+
{
11+
public partial class Home
12+
{
13+
[SupplyParameterFromQuery(Name = "hub")]
14+
public string? HubKey { get; set; }
15+
16+
private string _authorizationCode = default!;
17+
private string _codeVerifier = default!;
18+
19+
private string? _username;
20+
private string? _password;
21+
22+
private UALoginForm _form = null!;
23+
24+
protected bool Ready;
25+
protected string? Error;
26+
27+
protected override async Task OnAfterRenderAsync(bool firstRender)
28+
{
29+
if (firstRender)
30+
{
31+
//await HubContextInitializer.EnsureInitializedAsync();
32+
}
33+
}
34+
35+
private async Task InitializeHubContext()
36+
{
37+
if (string.IsNullOrWhiteSpace(HubKey))
38+
return;
39+
40+
var artifact = await AuthStore.ConsumeAsync(new AuthArtifactKey(HubKey));
41+
42+
if (artifact is not HubFlowArtifact flow)
43+
return;
44+
45+
var context = new UAuthHubContext(
46+
hubSessionId: flow.HubSessionId,
47+
flowType: flow.FlowType,
48+
clientProfile: flow.ClientProfile,
49+
tenantId: flow.TenantId,
50+
returnUrl: flow.ReturnUrl,
51+
payload: flow.Payload,
52+
createdAt: DateTimeOffset.UtcNow);
53+
54+
HubContextAccessor.Initialize(context);
55+
56+
StateHasChanged();
57+
}
58+
59+
private async Task ProgrammaticPkceLogin()
60+
{
61+
var hub = HubContextAccessor.Current;
62+
63+
if (hub is null)
64+
return;
65+
66+
hub.Payload.TryGet("authorization_code", out string? authorizationCode);
67+
hub.Payload.TryGet("code_verifier", out string? codeVerifier);
68+
hub.Payload.TryGet("return_url", out string? returnUrl);
69+
70+
var request = new PkceLoginRequest
71+
{
72+
Identifier = "Admin",
73+
Secret = "Password!",
74+
AuthorizationCode = authorizationCode ?? string.Empty,
75+
CodeVerifier = codeVerifier ?? string.Empty,
76+
ReturnUrl = hub.ReturnUrl ?? string.Empty
77+
};
78+
await UAuthClient.CompletePkceLoginAsync(request);
79+
}
80+
81+
//protected override void OnAfterRender(bool firstRender)
82+
//{
83+
// if (firstRender)
84+
// {
85+
// var uri = Nav.ToAbsoluteUri(Nav.Uri);
86+
// var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
87+
88+
// if (query.TryGetValue("error", out var error))
89+
// {
90+
// ShowLoginError(error.ToString());
91+
// ClearQueryString();
92+
// }
93+
// }
94+
//}
95+
96+
private void ShowLoginError(string code)
97+
{
98+
var message = code switch
99+
{
100+
"invalid" => "Invalid username or password.",
101+
"locked" => "Your account is locked.",
102+
"mfa" => "Multi-factor authentication required.",
103+
_ => "Login failed."
104+
};
105+
106+
Snackbar.Add(message, Severity.Error);
107+
}
108+
109+
private void ClearQueryString()
110+
{
111+
var uri = new Uri(Nav.Uri);
112+
var clean = uri.GetLeftPart(UriPartial.Path);
113+
Nav.NavigateTo(clean, replace: true);
114+
}
115+
116+
}
117+
}
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)