diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Abstraction/IAuthenticationStore.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Abstraction/IAuthenticationStore.cs index b4f5a84..7f6dbe4 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Abstraction/IAuthenticationStore.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Abstraction/IAuthenticationStore.cs @@ -2,9 +2,29 @@ namespace Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.Abstraction; +/// +/// Authentication store interface +/// public interface IAuthenticationStore { + /// + /// Deletes a scope + /// + /// The scope void Delete(string scope); + + /// + /// Gets for a scope + /// + /// + /// The stored entity Task GetAsync(string scope); + + /// + /// Sets for a scope + /// + /// The scope + /// The entity to store + /// Task SetAsync(string scope, AuthenticationEntity value); } \ No newline at end of file diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.csproj b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.csproj index 8fc1965..6b87441 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.csproj +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.csproj @@ -17,6 +17,18 @@ ..\..\.sonarlint\aguafrommars_maui.blazor.authenticationcsharp.ruleset README.md false + Olivier Lefebvre + Simplify OIDC authentication for MAUI Blazor app. + Copyright (c) 2023 @Olivier Lefebvre + https://github.com/Aguafrommars/Maui.Blazor.Authentication/tree/main/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc + https://github.com/Aguafrommars/Maui.Blazor.Authentication + git + + openid-connect;oidc;openidconnect-client;maui;blazor;maui-blazor;auhtentication + Apache-2.0 + package-icon.png + Maui.Blazor.Authentication + True @@ -30,7 +42,9 @@ - + + + + - diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/AuthenticationEntity.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/AuthenticationEntity.cs index 7575f14..6d2e439 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/AuthenticationEntity.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/AuthenticationEntity.cs @@ -1,17 +1,47 @@ namespace Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.Models; +/// +/// Define an authentication +/// public record AuthenticationEntity { + /// + /// Collection of claims + /// public IEnumerable Claims { get; init; } + /// + /// Access token + /// public string AccessToken { get; set; } + /// + /// Refresh token + /// public string RefreshToken { get; set; } + /// + /// Identity token + /// public string IdentityToken { get; set; } + /// + /// Access token expiration date + /// public DateTimeOffset AccessTokenExpiration { get; set; } + + /// + /// Type of authentication + /// public string AuthenticationType { get; init; } + + /// + /// Type of role claim + /// public string RoleClaintType { get; init; } + + /// + /// Type of name claim + /// public string NameClaimType { get; init; } } \ No newline at end of file diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/ClaimEntity.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/ClaimEntity.cs index cde7314..9cb3476 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/ClaimEntity.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Models/ClaimEntity.cs @@ -1,8 +1,17 @@ namespace Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.Models; +/// +/// Define a claim +/// public record ClaimEntity { + /// + /// Claim type + /// public string Type { get; init; } + /// + /// Claim value + /// public string Value { get; init; } } \ No newline at end of file diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Platforms/Windows/WebAuthenticator.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Platforms/Windows/WebAuthenticator.cs index c8f2953..06e6225 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Platforms/Windows/WebAuthenticator.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Platforms/Windows/WebAuthenticator.cs @@ -24,6 +24,9 @@ namespace WinUIEx; /// internal sealed class WebAuthenticator: IWebAuthenticator { + /// + /// Singleton instance of + /// public static readonly WebAuthenticator Instance = new(); private readonly Dictionary> tasks = new(); @@ -32,11 +35,16 @@ internal sealed class WebAuthenticator: IWebAuthenticator private WebAuthenticator() { - _appInstance = AppLifecycle.AppInstance.GetCurrent() ?? throw new InvalidOperationException("The WebAuthenticator requires an app instance"); ; - _package = Package.Current ?? throw new InvalidOperationException("The WebAuthenticator requires a packaged app with an AppxManifest"); ; + _appInstance = AppLifecycle.AppInstance.GetCurrent() ?? throw new InvalidOperationException("The WebAuthenticator requires an app instance"); + _package = Package.Current ?? throw new InvalidOperationException("The WebAuthenticator requires a packaged app with an AppxManifest"); SubcribeToActivated(_appInstance); } + /// + /// Anthenticates the user + /// + /// The authentication options + /// public Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions) => AuthenticateAsync(webAuthenticatorOptions.Url, webAuthenticatorOptions.CallbackUrl); @@ -54,6 +62,10 @@ internal static void Init() Trace.WriteLine($"WinUIEx: Failed to initialize the WebAuthenticator: {ex.Message}", "WinUIEx"); } } + + /// + /// Method call on application initialization. + /// public void OnAppCreation() { var activatedEventArgs = _appInstance?.GetActivatedEventArgs(); diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/OidcAuthenticationService.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/OidcAuthenticationService.cs index b57e81d..492770b 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/OidcAuthenticationService.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/OidcAuthenticationService.cs @@ -10,6 +10,10 @@ namespace Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.Services; +/// +/// OIDC authentication service +/// +/// public class OidcAuthenticationService : AuthenticationStateProvider, IRemoteAuthenticationService, @@ -36,6 +40,13 @@ private DateTimeOffset ExpireAt } } + /// + /// Initialize a new instance of + /// + /// An + /// A + /// A + /// public OidcAuthenticationService(OidcClient oidcClient, IAuthenticationStore store, NavigationManager navigation, @@ -47,12 +58,15 @@ public OidcAuthenticationService(OidcClient oidcClient, _options = options; } + /// public Task> CompleteSignInAsync(RemoteAuthenticationContext context) => throw new NotImplementedException(); + /// public Task> CompleteSignOutAsync(RemoteAuthenticationContext context) => throw new NotImplementedException(); + /// public override async Task GetAuthenticationStateAsync() { if (ExpireAt < DateTimeOffset.Now.AddMinutes(5)) @@ -74,12 +88,14 @@ public override async Task GetAuthenticationStateAsync() return new AuthenticationState(_principal); } + /// public ValueTask RequestAccessToken() => RequestAccessToken(new AccessTokenRequestOptions { Scopes = _options.Value.ProviderOptions.DefaultScopes }); + /// public async ValueTask RequestAccessToken(AccessTokenRequestOptions options) { var authentication = await GetAuthenticationAsync(string.Join(' ', options.Scopes)).ConfigureAwait(false); @@ -99,6 +115,7 @@ public async ValueTask RequestAccessToken(AccessTokenRequestO } : null); } + /// public async Task> SignInAsync(RemoteAuthenticationContext context) { var result = await _oidcClient.LoginAsync().ConfigureAwait(false); @@ -114,6 +131,7 @@ public async Task> SignIn }; } + /// public async Task> SignOutAsync(RemoteAuthenticationContext context) { await Task.Factory.StartNew(() => _oidcClient.LogoutAsync()); diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/WebBrowserAuthenticator.cs b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/WebBrowserAuthenticator.cs index b1b50b1..4f47e7b 100644 --- a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/WebBrowserAuthenticator.cs +++ b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/Services/WebBrowserAuthenticator.cs @@ -4,15 +4,23 @@ namespace Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc.Services; +/// +/// Web browser authenticator +/// public class WebBrowserAuthenticator : IBrowser { private readonly IWebAuthenticator _authenticator; + /// + /// Initialize a new instance of + /// + /// public WebBrowserAuthenticator(IWebAuthenticator authenticator) { _authenticator = authenticator; } + /// public async Task InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default) { try diff --git a/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/package-icon.png b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/package-icon.png new file mode 100644 index 0000000..623b028 Binary files /dev/null and b/src/Aguacongas.AspNetCore.Components.Maui.Authentication.Oidc/package-icon.png differ