1- using CodeBeam . UltimateAuth . Client ;
1+ using CodeBeam . UltimateAuth . Client . Contracts ;
2+ using CodeBeam . UltimateAuth . Client . Utilities ;
23using CodeBeam . UltimateAuth . Core . Contracts ;
34using CodeBeam . UltimateAuth . Core . Domain ;
4- using CodeBeam . UltimateAuth . Server . Infrastructure ;
55using CodeBeam . UltimateAuth . Server . Stores ;
66using Microsoft . AspNetCore . Components ;
7- using Microsoft . AspNetCore . Components . Authorization ;
87using Microsoft . AspNetCore . WebUtilities ;
98using MudBlazor ;
10- using System ;
119
1210namespace CodeBeam . UltimateAuth . Sample . UAuthHub . Components . Pages
1311{
@@ -16,68 +14,75 @@ public partial class Home
1614 [ SupplyParameterFromQuery ( Name = "hub" ) ]
1715 public string ? HubKey { get ; set ; }
1816
19- private string _authorizationCode = default ! ;
20- private string _codeVerifier = default ! ;
21-
2217 private string ? _username ;
2318 private string ? _password ;
2419
25- private UALoginForm _form = null ! ;
20+ private HubFlowState ? _state ;
21+
22+ protected override async Task OnParametersSetAsync ( )
23+ {
24+ if ( string . IsNullOrWhiteSpace ( HubKey ) )
25+ {
26+ _state = null ;
27+ return ;
28+ }
2629
27- protected bool Ready ;
28- protected string ? Error ;
30+ _state = await HubFlowReader . GetStateAsync ( new HubSessionId ( HubKey ) ) ;
31+ }
2932
3033 protected override async Task OnAfterRenderAsync ( bool firstRender )
3134 {
3235 if ( ! firstRender )
3336 return ;
3437
35- var hubKey = GetHubKeyFromQuery ( ) ;
38+ var currentError = await BrowserStorage . GetAsync ( StorageScope . Session , "uauth:last_error" ) ;
3639
37- if ( hubKey is null )
40+ if ( ! string . IsNullOrWhiteSpace ( currentError ) )
3841 {
39- await StartNewPkceAsync ( ) ;
40- return ;
42+ Snackbar . Add ( ResolveErrorMessage ( currentError ) , Severity . Error ) ;
43+ await BrowserStorage . RemoveAsync ( StorageScope . Session , "uauth:last_error" ) ;
4144 }
4245
43- var state = await HubStateReader . GetStateAsync ( hubKey ) ;
46+ var uri = Nav . ToAbsoluteUri ( Nav . Uri ) ;
47+ var query = QueryHelpers . ParseQuery ( uri . Query ) ;
4448
45- if ( ! state . Exists || ! state . IsActive )
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 ) )
4655 {
47- await StartNewPkceAsync ( ) ;
4856 return ;
4957 }
50- }
5158
52- private string ? GetHubKeyFromQuery ( )
53- {
54- var uri = Nav . ToAbsoluteUri ( Nav . Uri ) ;
55- var query = Microsoft . AspNetCore . WebUtilities . QueryHelpers . ParseQuery ( uri . Query ) ;
56-
57- if ( query . TryGetValue ( "hub" , out var hubKey ) && ! string . IsNullOrWhiteSpace ( hubKey ) )
58- return hubKey ;
59+ if ( _state is null || ! _state . Exists )
60+ return ;
5961
60- return null ;
62+ if ( _state ? . IsActive != true )
63+ {
64+ await StartNewPkceAsync ( ) ;
65+ return ;
66+ }
6167 }
6268
69+ // For testing & debugging
6370 private async Task ProgrammaticPkceLogin ( )
6471 {
65- var hub = HubContextAccessor . Current ;
72+ var hub = _state ;
6673
6774 if ( hub is null )
6875 return ;
6976
70- hub . Payload . TryGet ( "authorization_code" , out string ? authorizationCode ) ;
71- hub . Payload . TryGet ( "code_verifier" , out string ? codeVerifier ) ;
72- hub . Payload . TryGet ( "return_url" , out string ? returnUrl ) ;
77+ var credentials = await HubCredentialResolver . ResolveAsync ( new HubSessionId ( HubKey ) ) ;
7378
7479 var request = new PkceLoginRequest
7580 {
7681 Identifier = "Admin" ,
7782 Secret = "Password!" ,
78- AuthorizationCode = authorizationCode ?? string . Empty ,
79- CodeVerifier = codeVerifier ?? string . Empty ,
80- ReturnUrl = hub . ReturnUrl ?? string . Empty
83+ AuthorizationCode = credentials ? . AuthorizationCode ?? string . Empty ,
84+ CodeVerifier = credentials ? . CodeVerifier ?? string . Empty ,
85+ ReturnUrl = _state ? . ReturnUrl ?? string . Empty
8186 } ;
8287 await UAuthClient . CompletePkceLoginAsync ( request ) ;
8388 }
@@ -90,85 +95,38 @@ private async Task StartNewPkceAsync()
9095
9196 private async Task < string > ResolveReturnUrlAsync ( )
9297 {
93- // 1) Live hub context
94- var fromContext = HubContextAccessor . Current ? . ReturnUrl ;
98+ var fromContext = _state ? . ReturnUrl ;
9599 if ( ! string . IsNullOrWhiteSpace ( fromContext ) )
96100 return fromContext ;
97101
98- // 2) Query return_url (optional)
99102 var uri = Nav . ToAbsoluteUri ( Nav . Uri ) ;
100103 var query = Microsoft . AspNetCore . WebUtilities . QueryHelpers . ParseQuery ( uri . Query ) ;
101104
102105 if ( query . TryGetValue ( "return_url" , out var ru ) && ! string . IsNullOrWhiteSpace ( ru ) )
103106 return ru ! ;
104107
105- // 3) Query hub -> store lookup
106108 if ( query . TryGetValue ( "hub" , out var hubKey ) && ! string . IsNullOrWhiteSpace ( hubKey ) )
107109 {
108110 var artifact = await AuthStore . GetAsync ( new AuthArtifactKey ( hubKey ! ) ) ;
109111 if ( artifact is HubFlowArtifact flow && ! string . IsNullOrWhiteSpace ( flow . ReturnUrl ) )
110112 return flow . ReturnUrl ! ;
111113 }
112114
113- // 4) Config default (recommend adding to options)
115+ // Config default (recommend adding to options)
114116 //if (!string.IsNullOrWhiteSpace(_options.Login.DefaultReturnUrl))
115117 // return _options.Login.DefaultReturnUrl!;
116118
117- // 5) Final fallback (Hub URL)
118119 return Nav . Uri ;
119120 }
120-
121- private void CompleteHubFlow ( )
121+
122+ private string ResolveErrorMessage ( string ? errorKey )
122123 {
123- HubContextAccessor . Complete ( ) ;
124- StateHasChanged ( ) ;
125- }
126-
127- private void HandleErrorFromQuery ( )
128- {
129- var uri = Nav . ToAbsoluteUri ( Nav . Uri ) ;
130- var query = QueryHelpers . ParseQuery ( uri . Query ) ;
131-
132- if ( query . TryGetValue ( "error" , out var error ) )
124+ if ( errorKey == "invalid" )
133125 {
134- Snackbar . Add ( "Login failed." , Severity . Error ) ;
135- Nav . NavigateTo ( uri . GetLeftPart ( UriPartial . Path ) , replace : true ) ;
126+ return "Login failed." ;
136127 }
137- }
138-
139- //protected override void OnAfterRender(bool firstRender)
140- //{
141- // if (firstRender)
142- // {
143- // var uri = Nav.ToAbsoluteUri(Nav.Uri);
144- // var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
145-
146- // if (query.TryGetValue("error", out var error))
147- // {
148- // ShowLoginError(error.ToString());
149- // ClearQueryString();
150- // }
151- // }
152- //}
153-
154- private void ShowLoginError ( string code )
155- {
156- var message = code switch
157- {
158- "invalid" => "Invalid username or password." ,
159- "locked" => "Your account is locked." ,
160- "mfa" => "Multi-factor authentication required." ,
161- _ => "Login failed."
162- } ;
163128
164- Snackbar . Add ( message , Severity . Error ) ;
165- }
166-
167- private void ClearQueryString ( )
168- {
169- var uri = new Uri ( Nav . Uri ) ;
170- var clean = uri . GetLeftPart ( UriPartial . Path ) ;
171- Nav . NavigateTo ( clean , replace : true ) ;
129+ return "Failed attempt." ;
172130 }
173131
174132 }
0 commit comments