Secure Your Blazor App with Authelia OIDC
Implement self-hosted Single Sign-On (SSO) for Blazor Server using Authelia and OpenID Connect (OIDC).
Introduction
In a manufacturing environment or a homelab, you don’t want to manage separate passwords for your Wiki, your Dashboard, and your Document System. You want Single Sign-On (SSO).
Authelia is a lightweight authentication server that acts as your Identity Provider (IdP). Your Blazor app acts as the Client. They speak OpenID Connect (OIDC) to securely exchange user identity without your app ever touching a password.
Why Authelia OIDC?
- Centralized User Management: One place to ban users or reset passwords.
- 2FA Enforcement: Authelia handles TOTP/Duo; your app doesn’t need to know.
- Standard Protocol: If you switch to Entra ID (Azure AD) later, the code changes are minimal.
What We’ll Build
- Authelia Config: Register your Blazor app as a client.
- Blazor Program.cs: Configure the OIDC middleware.
- Token Handling: Map claims from Authelia (groups, email) to .NET ClaimsPrincipal.
Architecture Overview
sequenceDiagram
participant User
participant Blazor as 🛡️ Blazor App
participant Authelia as 🔐 Authelia (IdP)
User->>Blazor: Access Protected Page
Blazor->>User: 302 Redirect to Authelia
User->>Authelia: Login (User + Pass + 2FA)
Authelia->>User: 302 Redirect to /signin-oidc?code=XYZ
User->>Blazor: GET /signin-oidc?code=XYZ
Blazor->>Authelia: POST /api/oidc/token (Exchange Code)
Authelia->>Blazor: Return ID Token + Access Token
Blazor->>User: Set Auth Cookie (Session Established)
User->>Blazor: Request Page
Blazor->>User: Render Authorized Content
Section 1: Authelia Configuration
First, tell Authelia about your application. It needs a client_id and a client_secret.
# configuration.yml (Authelia)
identity_providers:
oidc:
clients:
- client_id: bluerobin-web
client_name: BlueRobin Web
client_secret: '$pbkdf2-sha512$...' # Hashed secret
public: false
authorization_policy: two_factor # Force 2FA
redirect_uris:
- https://web.bluerobin.local/signin-oidc
scopes:
- openid
- profile
- email
- groups
token_endpoint_auth_method: client_secret_post
Section 2: .NET 8/9 Configuration
In Program.cs, we use the standard Microsoft.AspNetCore.Authentication.OpenIdConnect library.
// Program.cs
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.Cookie.Name = "BlueRobin.Session";
options.Cookie.SameSite = SameSiteMode.Lax;
})
.AddOpenIdConnect(options =>
{
options.Authority = "https://auth.bluerobin.local";
options.ClientId = "bluerobin-web";
options.ClientSecret = builder.Configuration["Auth:ClientSecret"];
options.ResponseType = "code";
// Scopes request specific data
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("groups");
// Map Authelia's "groups" claim to .NET's Role claim
options.TokenValidationParameters = new()
{
NameClaimType = "preferred_username",
RoleClaimType = "groups"
};
// Secure by default
options.RequireHttpsMetadata = true;
options.SaveTokens = true;
});
Section 3: Protecting Pages
In Blazor, use [Authorize] to protect pages.
@page "/dashboard"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
<h1>Dashboard</h1>
<p>Welcome, @context.User.Identity?.Name!</p>
@if (context.User.IsInRole("admin"))
{
<button class="btn-danger">Delete Database</button>
}
Conclusion
By offloading authentication to Authelia, you make your application simpler and more secure. You no longer store password hashes. You get multi-factor authentication “for free”. And your users get a seamless Single Sign-On experience across your entire suite of apps.