Skip to content

OurAuth/ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect

 
 

Repository files navigation

ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect

A JavaScript free OpenID Connect PKCE library for Blazor WebAssembly.

The library support login and logout with OpenID Connect (OIDC) using Proof Key for Code Exchange (PKCE) instead of a client secret.

Please see the sample application for implementation details.

Install

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

Setup and configuration

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.

API calls to another domain

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...",
    "AuthorizedUris": [ "...authorized api uri..." ]
  }
}

Add call back page

Add a Authentication.razor call back page in the Pages folder with the following content.

@page "/authentication/{action}"
@inherits AuthenticationPageBase

Authorize views

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.

Login / logout menu

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>

Support

If you have questions please ask them on Stack Overflow. Then email a link to support@itfoxtec.com and I will answer as soon as possible.

About

ITfoxtec Identity for Blazor WebAssembly implement OpenID Connect with PKCE.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 99.4%
  • HTML 0.6%