A JavaScript free OpenID Connect PKCE library for Blazor WebAssembly.
- Support .NET 8.0
- Support .NET 7.0
- Support .NET 6.0
- Support .NET 5.0
The library support login and logout with OpenID Connect (OIDC) using Proof Key for Code Exchange (PKCE) instead of a client secret.
The received ID token is validated by the component in the client using the OpenID Provider (OP) discovery document.
The component automatically handle token / session update with use of refresh tokens if the offline_access scope is specified.
Please see the sample application for implementation details.
The sample application is configured to authenticate with foxids.com using test user[email protected]
or[email protected]
and passwordTestAccess!
For more information about the open source FoxIDs please see the FoxIDs documentation.
Install the ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect NuGet package via the Visual Studio package manger.
Or install via PowerShell using the following command.
Install-Package ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect
Or via CLI.
dotnet add package ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect
Register the OpenidConnectPkce, the HttpClient and the IHttpClientFactory in the Program.cs file.
private static void ConfigureServices(IServiceCollection services, WebAssemblyHostConfiguration configuration, IWebAssemblyHostEnvironment hostEnvironment)
{
services.AddHttpClient("BlazorWebAssemblyOidcSample.API", client => client.BaseAddress = new Uri(hostEnvironment.BaseAddress))
.AddHttpMessageHandler<AccessTokenMessageHandler>();
services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorWebAssemblyOidcSample.API"));
services.AddOpenidConnectPkce(settings =>
{
configuration.Bind("IdentitySettings", settings);
});
}
Add appsettings.json and possible appsettings.Development.json configuration files under wwwroot with the IdentitySettings configuration. The scope is added as a space separated list of values.
{
"IdentitySettings": {
"Authority": "https://...some authority.../",
"ClientId": "...client id...",
"Scope": "...some scope..."
}
}
Add the library namespace @using ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect
to _Imports.razor.
Configuration the Blazor client as a OpenID Connect client on the IdP.
Response types: code
Enable PKCE: true
Login call back: ...base URL.../authentication/login_callback
Logout call back: ...base URL.../authentication/logout_callback
The configuration can be expanded to support API calls to another domains then the base domain. The trusted AuthorizedUris in the IdentitySettings configuration is configured on the AccessTokenMessageHandler.
private static void ConfigureServices(IServiceCollection services, WebAssemblyHostConfiguration configuration, IWebAssemblyHostEnvironment hostEnvironment)
{
services.AddHttpClient("BlazorWebAssemblyOidcSample.API", client => client.BaseAddress = new Uri(hostEnvironment.BaseAddress))
.AddHttpMessageHandler(sp =>
{
var handler = sp.GetService<AccessTokenMessageHandler>();
configuration.Bind("IdentitySettings", handler);
return handler;
});
services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorWebAssemblyOidcSample.API"));
services.AddOpenidConnectPkce(settings =>
{
configuration.Bind("IdentitySettings", settings);
});
}
Add trusted domains as AuthorizedUris in the IdentitySettings configuration.
{
"IdentitySettings": {
"Authority": "https://...some authority.../",
"ClientId": "...client id...",
"Scope": "...some scope...",
"Resources": [ "...resource..." ],
"AuthorizedUris": [ "...authorized api Uri..." ]
}
}
Add a Authentication.razor call back page in the Pages folder with the following content.
@page "/authentication/{action}"
@inherits AuthenticationPageBase
Update the App.razor to include AuthorizeRouteView/NotAuthorized with the OidcRedirectToLogin element. The OidcRedirectToLogin start the login flow if the user do not have access.
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
<OidcRedirectToLogin />
</NotAuthorized>
<Authorizing>
<h1>Authentication in progress</h1>
<p>Only visible while authentication is in progress.</p>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)">
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</CascadingAuthenticationState>
</NotFound>
</Router>
Thereby both the Authorize attribute and AuthorizeView are supported.
Possible add the LoginDisplay.razor with a login / logout menu with the following content.
@inject OpenidConnectPkce oenidConnectPkce
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<button class="nav-link btn btn-link" @onclick="LogoutAsync">Logout</button>
</Authorized>
<NotAuthorized>
<button class="nav-link btn btn-link" @onclick="LoginAsync">Login</button>
</NotAuthorized>
</AuthorizeView>
@code{
private async Task LoginAsync(MouseEventArgs args)
{
await oenidConnectPkce.LoginAsync();
}
private async Task LogoutAsync(MouseEventArgs args)
{
await oenidConnectPkce.LogoutAsync();
}
}
The LoginDisplay can be added to the MainLayout.razor like this.
@inherits LayoutComponentBase
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
<LoginDisplay />
</div>
<div class="content px-4">
@Body
</div>
</div>
If you have questions please ask them on Stack Overflow. Tag your questions with 'itfoxtec-identity-blazor' and I will answer as soon as possible.