Security Intermediate 14 min

Secure Your Blazor App with Authelia OIDC

Implement self-hosted Single Sign-On (SSO) for Blazor Server using Authelia and OpenID Connect (OIDC).

By Victor Robin Updated:

Introduction

Before integrating Authelia, BlueRobin’s web app had its own user table with bcrypt-hashed passwords and a hand-rolled JWT system. It worked, but every new feature—password reset, 2FA, session management—was another surface area to secure. Migrating to Authelia OIDC deleted over 2,000 lines of authentication code and replaced it with 40 lines of Program.cs configuration. The security posture improved dramatically because I was no longer responsible for implementing cryptographic protocols correctly.

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. [OpenID Connect Core 1.0] — OpenID Foundation , 2014

Why Authelia OIDC?

What We’ll Build

  1. Authelia Config: Register your Blazor app as a client.
  2. Blazor Program.cs: Configure the OIDC middleware.
  3. 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: my-web-client
        client_name: My Web App
        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
[OAuth 2.0 Security Best Current Practice] — IETF , 2023

Section 2: .NET 8/9 Configuration

In Program.cs, we use the standard Microsoft.AspNetCore.Authentication.OpenIdConnect library. [ASP.NET Core Authentication] — Microsoft , 2024

// 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 = "MyApp.Session";
    options.Cookie.SameSite = SameSiteMode.Lax;
})
.AddOpenIdConnect(options =>
{
    options.Authority = "https://auth.bluerobin.local";
    options.ClientId = "my-web-client";
    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>
}
[Blazor Authentication and Authorization] — Microsoft , 2024

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.

The migration from custom auth to Authelia OIDC was one of the highest-ROI changes I’ve made to BlueRobin. Not only did it eliminate an entire class of security vulnerabilities (password storage, session fixation, CSRF on login forms), but it also enabled features I hadn’t planned for—like group-based access control that lets me share specific sections of the app with family members without giving them admin access.

Next Steps:

Further Reading