Introduction

BitzArt.Blazor.Auth is a Blazor library that provides tearless authentication and authorization capabilities for your Blazor applications. Thanks to Blazor.Cookies, it works with all Blazor United render modes.

Blazor RendermodeSupportSign-InSign-UpSign-Out
Static SSR✔️✔️✔️✔️
Interactive WebAssembly✔️✔️✔️✔️
Interactive Server✔️✔️✔️✔️
Interactive Auto✔️✔️✔️✔️

Getting Started

Refer to the Getting Started section to learn how to use this library in your Blazor applications.

Getting Started

Installation

Add this nuget package to your Server project:

dotnet add package BitzArt.Blazor.Auth.Server

Add this nuget package to your Client project:

dotnet add package BitzArt.Blazor.Auth.Client

Configuration

Call this method in both your Server Program.cs and Client Program.cs:

builder.AddBlazorAuth();

Usage

You can now use Blazor authorization capabilities (such as @attribute [Authorize], AuthorizeView, AuthorizeRouteView) as you normally would.

What's next?

Refer to the Authentication section to learn how to customize your authentication logic.

Authentication

💡 You can always refer to the sample project for additional guidance.

In order to implement User authentication with this library, you need to implement the IAuthenticationService in your Blazor Server project and specify it when calling the AddBlazorAuth method in your Blazor Server Program.cs file.

Implementation

Sign-In Payload

Create a class for your Sign-In payload. This class will be used to pass the user's credentials to the IAuthenticationService implementation.

Note
This class needs to be serializable, so it can be passed between the Client and Server projects over http.

// Example Sign-In payload
public class SignInPayload
{
    public string Email { get; set; }
    public string Password { get; set; }
}

Authentication Service

You can inherit from the base AuthenticationService class, or implement the IAuthenticationService interface directly.

// Example Authentication Service
public class MyAmazingAuthenticationService : AuthenticationService<SignInPayload>
{
    public override Task<AuthenticationResult> SignInAsync(SignInPayload signInPayload, CancellationToken cancellationToken = default)
    {
        var jwtPair = BuildJwtPair();
        var authResult = Success(jwtPair);

        return Task.FromResult(authResult);
    }

    public override Task<AuthenticationResult> RefreshJwtPairAsync(string refreshToken, CancellationToken cancellationToken = default)
    {
        var jwtPair = BuildJwtPair();
        var authResult = Success(jwtPair);

        return Task.FromResult(authResult);
    }

    private JwtPair BuildJwtPair()
    {
        return new JwtPair
        {
            AccessToken = "access-token-goes-here",
            RefreshToken = "refresh-token-goes-here"
        };
    }
}

Register the Authentication Service

Specify your IAuthenticationService implementation when calling the AddBlazorAuth method in your Blazor Server Program.cs file.

// Program.cs
builder.AddBlazorAuth<MyAmazingAuthenticationService>();

Add the authentication endpoints in your Blazor Server Program.cs. This is required in order to allow the Client project to call the Server's API and use the server-side IAuthenticationService implementation.

// Program.cs
app.MapAuthEndpoints();

User Service

You can now use IUserService in your Blazor Pages to sign the user in:

// MyPage.razor

[Inject] IUserService<SignInPayload> UserService { get; set; }

private async Task SignInAsync()
{
    // Simulating user input
    var signInPayload = new SignInPayload("some data");

    // Signing the user in
    var authenticationResult = await UserService.SignInAsync(signInPayload);

    // Refresh the page after signing in
    // to let Blazor know that the user's authentication state has changed
    NavigationManager.NavigateTo(NavigationManager.Uri, true);
}

For additional guidance, see sample flows in Use Cases section.

Token duration

You can specify the duration of your access token and refresh token whenever you are providing your JwtPair to Blazor.Auth. The duration of the access token should normally be short, while the refresh token should normally be long-lived.

return new JwtPair
    {
        AccessToken = "access-token-goes-here",
        RefreshToken = "refresh-token-goes-here",
        AccessTokenExpiresAt = DateTimeOffset.UtcNow.AddMinutes(15),
        RefreshTokenExpiresAt = DateTimeOffset.UtcNow.AddDays(7)
    }

⚠️ Not providing an expiration date for the tokens will result in them being session-scoped. This means that the tokens will expire when the browser tab closes.

Sign out

You can sign the user out by calling the SignOutAsync method of the IUserService. This will clear the user's token cookies.

await UserService.SignOutAsync();
NavigationManager.NavigateTo("/", true);

Sign Up

Implementation

Sign-Up Payload

Create a class for your Sign-Up payload, similarly to how you would for the Sign-In payload. This class will be used to pass the user's sign-up request details to the IAuthenticationService implementation.

Note
This class needs to be serializable, so it can be passed between the Client and Server projects over http.

// Example Sign-Up payload
public class SignUpPayload
{
    public string Email { get; set; }
    public string Password { get; set; }
}

Authentication Service

Use your Sign-Up payload class as a second generic parameter in your IAuthenticationService implementation. You can inherit from the base AuthenticationService class, or implement the IAuthenticationService interface directly.

// Example Authentication Service
public class MyAmazingAuthenticationService : AuthenticationService<SignInPayload, SignUpPayload>
{
    // Sign-In and other methods omitted for brevity

    public override Task<AuthenticationResult> SignUpAsync(SignUpPayload signUpPayload, CancellationToken cancellationToken = default)
    {
        var jwtPair = BuildJwtPair();
        var authResult = Success(jwtPair);

        return Task.FromResult(authResult);
    }

    // ...
}

User Service

You can now use IUserService in your Blazor Pages to sign the user up:

// MyPage.razor

[Inject] IUserService<SignInPayload, SignUpPayload> UserService { get; set; }

private async Task SignUpAsync()
{
    // Simulating user input
    var signUpPayload = new SignUpPayload("some data");

    // Signing the user up
    var authenticationResult = await UserService.SignUpAsync(signUpPayload);

    // Refresh the page after signing up
    // to let Blazor know that the user's authentication state has changed
    NavigationManager.NavigateTo(NavigationManager.Uri, true);
}

For additional guidance, see sample flows in Use Cases section.

Use Cases

While your end soultion code regarding authentication remains the same, the way Blazor.Auth behaves under the hood may vary depending on your current render mode.

The following segments will guide you through the most common use-cases such as Sign-In, Sign-Up and Sign-Out and show you how to implement them in your Blazor application.

More detailed diagrams are organized according to different Blazor interactivity types:

Refresh Token

On every GetAuthenticationStateAsync call to AuthenticationStateProvider, it will check if the current access token is expired. If it is, the user's JWT Pair will automatically be refreshed.

Back to Use Cases

Static SSR

The following sequence diagrams illustrate the use cases for Blazor.Auth in a Blazor application that is currently using Static SSR render mode.

For the purposes of these sample flows, an approach utilizing form submission is used. For more information on how Blazor handles form submission in Static SSR, refer to Blazor Documentation. You can use any other approach, as long as it is compatible with Static SSR. Just resolve the IUserService from the DI container and call it's appropriate method - Blazor.Auth will take care of the rest.

Sign-In

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userService as IUserService (Server)
end
participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-In Form

page ->>+ userService: SignInAsync(signInPayload)
note over user,userService: Call IUserService's `SignInAsync` method when handling sign-in form submission.

userService ->>+ authService: SignInAsync(signInPayload)
authService ->> authService: Your server-side sign-in logic

authService -->>- userService: AuthenticationResult

userService -->> userService: Update authentication cookies
userService -->>- page: AuthenticationOperationInfo

page -->>- user:  Form submission HTTP Response
note over user,page: Updated cookies will be <br/> attached to the HTTP response.

Sign-Out

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userService as IUserService (Server)
end

user ->>+ page: Submit Sign-Out Form

page ->>+ userService: SignOutAsync()
note over user,userService: Call IUserService's `SignOutAsync` method when handling sign-out form submission.

userService -->> userService: Clear authentication cookies

userService -->>- page: 

page -->>- user:  Form submission HTTP Response
note over user,page: Blazor.Auth will clear the user's <br/> authentication cookies <br/> by marking them as expired <br/> in the HTTP response.

Sign-Up

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userService as IUserService (Server)
end
participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-Up Form

page ->>+ userService: SignUpAsync(signUpPayload)
note over user,userService: Call IUserService's `SignUpAsync` method when handling sign-up form submission.

userService ->>+ authService: SignUpAsync(signUpPayload)
authService ->> authService: Your server-side sign-up logic

authService -->>- userService: AuthenticationResult

userService -->> userService: Update authentication cookies
userService -->>- page: AuthenticationResult

page -->>- user:  Form submission HTTP Response
note over user,page: Updated cookies will be<br/>attached to the HTTP response.

Back to Use Cases

Interactive WebAssembly

The following sequence diagrams illustrate the use cases for Blazor.Auth in a Blazor application that is currently using Interactive WebAssembly render mode:

Sign-In

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceClient as IUserService (Client)
participant userServiceServer as Blazor Server
end

participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-In Form
page ->>+ userServiceClient: SignInAsync(signInPayload)
note over page,userServiceClient: Resolve IUserService <br/> from your DI container<br/> and call it's `SignInAsync` method.
userServiceClient ->>+ userServiceServer: HTTP request to Sign-In endpoint

userServiceServer ->>+ authService: SignInAsync(signInPayload)
authService ->> authService: Your server-side sign-in logic

authService -->>- userServiceServer: AuthenticationResult
userServiceServer -->> userServiceServer: Update authentication cookies
userServiceServer -->> userServiceClient: AuthenticationOperationInfo

note over userServiceClient,userServiceServer: Updated cookies will be<br/>attached to the HTTP response.

userServiceClient -->>- page: AuthenticationOperationInfo
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceClient: Upon receiving AuthenticationOperationInfo from IUserService, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).

Sign-Out

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceClient as IUserService (Client)
participant userServiceServer as Blazor Server
end

user ->>+ page: Initiate Sign-Out
page ->>+ userServiceClient: SignOutAsync()
note over page,userServiceClient: Resolve IUserService <br/> from your DI container<br/> and call it's `SignOutAsync` method.
userServiceClient ->>+ userServiceServer: HTTP request to Sign-Out endpoint

userServiceServer -->> userServiceServer: Clear authentication cookies
userServiceServer -->> userServiceClient: #32;

note over userServiceClient,userServiceServer: Blazor.Auth will clear the user's <br/> authentication cookies <br/> by marking them as expired <br/> in the HTTP response.

userServiceClient -->>- page: #32;
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceClient: Upon finishing method execution, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).

Sign-Up

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceClient as IUserService (Client)
participant userServiceServer as Blazor Server
end

participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-Up Form
page ->>+ userServiceClient: SignUpAsync(signUpPayload)
note over page,userServiceClient: Resolve IUserService <br/> from your DI container<br/> and call it's `SignInAsync` method.
userServiceClient ->>+ userServiceServer: HTTP request to Sign-Up endpoint

userServiceServer ->>+ authService: SignUpAsync(signUpPayload)
authService ->> authService: Your server-side sign-up logic

authService -->>- userServiceServer: AuthenticationResult
userServiceServer -->> userServiceServer: Update authentication cookies
userServiceServer -->> userServiceClient: AuthenticationOperationInfo

note over userServiceClient,userServiceServer: Updated cookies will be<br/>attached to the HTTP response.

userServiceClient -->>- page: AuthenticationOperationInfo
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceClient: Upon receiving AuthenticationOperationInfo from IUserService, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).

Back to Use Cases

Interactive Server

The following sequence diagrams illustrate the use cases for Blazor.Auth in a Blazor application that is currently using Interactive Server render mode:

Sign-In

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceServer as IUserService (Server)
participant blazorClient as Client Machine
participant blazorServer as Blazor Server
end

participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-In Form
page ->>+ userServiceServer: SignInAsync(signInPayload)
note over page,userServiceServer: Resolve IUserService from DI<br/> and call it's `SignInAsync` method.

userServiceServer ->>+ blazorClient: Remote JS Interop
blazorClient ->>+ blazorServer: HTTP Request to <br/> Sign-In endpoint
blazorServer ->>+ authService: SignInAsync(signInPayload)
authService ->> authService: Your server-side sign-in logic

authService -->>- blazorServer: AuthenticationResult
blazorServer -->> blazorServer: Update authentication cookies

blazorServer -->>- blazorClient: AuthenticationOperationInfo
note over blazorClient,blazorServer: Updated cookies will be<br/>attached to the HTTP response.

blazorClient -->>- userServiceServer: AuthenticationOperationInfo

userServiceServer -->>- page: AuthenticationOperationInfo
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceServer: Upon receiving AuthenticationOperationInfo from IUserService, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).

Sign-Out

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceServer as IUserService (Server)
participant blazorClient as Client Machine
participant blazorServer as Blazor Server
end

user ->>+ page: Submit Sign-Out Form
page ->>+ userServiceServer: SignOutAsync()
note over page,userServiceServer: Resolve IUserService from DI<br/> and call it's `SignOutAsync` method.

userServiceServer ->>+ blazorClient: Remote JS Interop
blazorClient ->>+ blazorServer: HTTP Request to <br/> Sign-Out endpoint

blazorServer -->> blazorServer: Clear authentication cookies

blazorServer -->>- blazorClient: #32;
note over blazorClient,blazorServer: Blazor.Auth will clear the user's <br/> authentication cookies <br/> by marking them as expired <br/> in the HTTP response.

blazorClient -->>- userServiceServer: #32;

userServiceServer -->>- page: #32;
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceServer: Upon finishing method execution, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).

Sign-Up

sequenceDiagram

actor user as User
participant page as Page

box rgba(101, 63, 232, 0.5) Blazor.Auth
participant userServiceServer as IUserService (Server)
participant blazorClient as Client Machine
participant blazorServer as Blazor Server
end

participant authService as IAuthenticationService (Server)

user ->>+ page: Submit Sign-Up Form
page ->>+ userServiceServer: SignUpAsync(signUpPayload)
note over page,userServiceServer: Resolve IUserService from DI<br/> and call it's `SignUpAsync` method.

userServiceServer ->>+ blazorClient: Remote JS Interop
blazorClient ->>+ blazorServer: HTTP Request to <br/> Sign-Up endpoint
blazorServer ->>+ authService: SignUpAsync(signUpPayload)
authService ->> authService: Your server-side sign-up logic

authService -->>- blazorServer: AuthenticationResult
blazorServer -->> blazorServer: Update authentication cookies

blazorServer -->>- blazorClient: AuthenticationOperationInfo
note over blazorClient,blazorServer: Updated cookies will be<br/>attached to the HTTP response.

blazorClient -->>- userServiceServer: AuthenticationOperationInfo

userServiceServer -->>- page: AuthenticationOperationInfo
page -->>- user: Continue, <br/> e.g. redirect to home page, <br/> or other custom logic

note over user,userServiceServer: Upon receiving AuthenticationOperationInfo from IUserService, <br/> do a page refresh in order to refresh the User's AuthenticationState<br/><br/> Example: NavigationManager.NavigateTo("/", true).