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 Rendermode | Support | Sign-In | Sign-Up | Sign-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).