Indiko.Hosting.BlazorServer 2.7.1

dotnet add package Indiko.Hosting.BlazorServer --version 2.7.1
                    
NuGet\Install-Package Indiko.Hosting.BlazorServer -Version 2.7.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Indiko.Hosting.BlazorServer" Version="2.7.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Indiko.Hosting.BlazorServer" Version="2.7.1" />
                    
Directory.Packages.props
<PackageReference Include="Indiko.Hosting.BlazorServer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Indiko.Hosting.BlazorServer --version 2.7.1
                    
#r "nuget: Indiko.Hosting.BlazorServer, 2.7.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Indiko.Hosting.BlazorServer@2.7.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Indiko.Hosting.BlazorServer&version=2.7.1
                    
Install as a Cake Addin
#tool nuget:?package=Indiko.Hosting.BlazorServer&version=2.7.1
                    
Install as a Cake Tool

Indiko.Hosting.BlazorServer

A complete Blazor Server hosting solution with built-in OpenID Connect authentication, PKCE support, security headers, and seamless Indiko Blocks integration.

NuGet License: MIT .NET 10


Features

  • Server-side Blazor — full SignalR hub wiring with optional authorization
  • OpenID Connect + PKCE — authorization code flow with PKCE, token saving, and claim mapping from the UserInfo endpoint
  • Cookie authentication — secure session management backed by OpenID Connect tokens
  • Security headers — CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy, CORP, COOP, COEP via NetEscapades.AspNetCore.SecurityHeaders
  • Forwarded headers — transparent reverse-proxy support
  • HTTPS redirection and HSTS — configurable per environment
  • Global authorization — optional AuthorizeFilter applied to all Razor Pages when auth is enabled
  • Controllers with Views — optional MVC controller support alongside Blazor
  • Development CORS — permissive policy in Development, no automatic CORS in Production
  • Indiko Blocks — blocks participating in ConfigureServices, Configure, ConfigureBuilder, and PreRunAsync lifecycle hooks
  • Flexible host builderConfigureHostBuilder(...) fluent API for Windows Service, containerization, and custom configurations
  • Options-driven or property-override configuration — choose the approach that fits your project

Installation

dotnet add package Indiko.Hosting.BlazorServer

Quick Start

1. Create your Startup class

using Indiko.Hosting.BlazorServer;

public class Startup : BlazorServerStartup
{
    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        : base(configuration, environment)
    {
    }

    // Optional: register additional services
    public override void ConfigureServices(IServiceCollection services)
    {
        base.ConfigureServices(services);
        services.AddScoped<IWeatherService, WeatherService>();
    }
}

2. Wire up Program.cs

// Program.cs
return await new BlazorServerHostBootstrapper()
    .RunAsync<Startup>(args);

3. Configure appsettings.json

{
  "ServiceName": "MyBlazorApp",
  "BlazorServerStartupOptions": {
    "AddControllersWithViews": false,
    "EnableForwardedHeaderOptions": true,
    "ForceHttps": false,
    "AddSecurityHeaderSupport": true,
    "AddOpenIdConfiguration": true,
    "AddAuthentication": true
  },
  "OpenIDConnectSettings": {
    "Authority": "https://identity.example.com",
    "ClientId": "blazor-client",
    "ClientSecret": "secret",
    "CallbackPath": "/signin-oidc"
  }
}

4. Add the _Host page

Blazor Server requires a Pages/_Host.cshtml Razor Page as the application shell. The bootstrapper maps it automatically via MapFallbackToPage("/_Host").


Configuration Approaches

There are two ways to configure startup options. Both work identically at runtime — choose whichever suits your project.

Add a BlazorServerStartupOptions section to appsettings.json. No code changes needed to toggle features between environments.

{
  "BlazorServerStartupOptions": {
    "AddControllersWithViews": false,
    "EnableForwardedHeaderOptions": true,
    "ForceHttps": false,
    "AddSecurityHeaderSupport": true,
    "AddOpenIdConfiguration": true,
    "AddAuthentication": true
  }
}

All properties default to false when the section is absent or a key is omitted.

Approach B: Property overrides in code

Override the protected virtual properties in your Startup subclass. This approach is useful when options are determined by logic rather than configuration, or when you want compile-time guarantees.

public class Startup : BlazorServerStartup
{
    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        : base(configuration, environment)
    {
    }

    protected override bool AddControllersWithViews      => false;
    protected override bool EnableForwardedHeaderOptions => true;
    protected override bool ForceHttps                  => false;
    protected override bool AddSecurityHeaderSupport     => true;
    protected override bool AddOpenIdConfiguration       => true;
    protected override bool AddAuthentication            => true;
}

Precedence: Property overrides in your subclass always win. The base implementation of each property reads from BlazorServerStartupOptions, so if you do not override a property, the appsettings.json value applies.


Startup Options Reference

Option Type Default Description
AddControllersWithViews bool false Register MVC controllers alongside Blazor. When auth is also enabled, AutoValidateAntiforgeryTokenAttribute is applied globally.
EnableForwardedHeaderOptions bool false Enable UseForwardedHeaders() for reverse-proxy deployments.
ForceHttps bool false Add UseHttpsRedirection() middleware.
AddSecurityHeaderSupport bool false Apply security headers (CSP, X-Frame-Options, etc.) via NetEscapades. Requires OpenIDConnectSettings.Authority to be set.
AddOpenIdConfiguration bool false Configure the OpenID Connect handler. Usually paired with AddAuthentication.
AddAuthentication bool false Enable cookie + OpenID Connect authentication. Automatically applies global RequireAuthenticatedUser policy on Razor Pages and RequireAuthorization() on the Blazor hub.

EnableForwardedHeaderOptions and ForceHttps are inherited from HostStartupOptions (defined in Indiko.Hosting.Abstractions).


Flexible Host Builder

Because BlazorServerHostBootstrapper is sealed, the fluent ConfigureHostBuilder method is the extension point for host-level configuration:

// Windows Service
return await new BlazorServerHostBootstrapper()
    .ConfigureHostBuilder(b => b.UseWindowsService())
    .RunAsync<Startup>(args);

// Systemd (Linux)
return await new BlazorServerHostBootstrapper()
    .ConfigureHostBuilder(b => b.UseSystemd())
    .RunAsync<Startup>(args);

// Custom Kestrel configuration
return await new BlazorServerHostBootstrapper()
    .ConfigureHostBuilder(b => b.ConfigureWebHostDefaults(web =>
        web.ConfigureKestrel(k => k.ListenAnyIP(8080))))
    .RunAsync<Startup>(args);

// Chain multiple calls
return await new BlazorServerHostBootstrapper()
    .ConfigureHostBuilder(b => b.UseWindowsService())
    .ConfigureHostBuilder(b => b.ConfigureLogging(l => l.AddConsole()))
    .RunAsync<Startup>(args);

Host builder actions are applied after all Indiko Block ConfigureBuilder calls, in the order they are registered.


OpenID Connect Setup

Authentication requires both AddAuthentication and AddOpenIdConfiguration to be true.

appsettings.json

{
  "OpenIDConnectSettings": {
    "Authority": "https://identity.example.com",
    "ClientId": "blazor-client",
    "ClientSecret": "secret",
    "CallbackPath": "/signin-oidc"
  }
}

What the bootstrapper configures automatically

  • DefaultScheme: Cookie
  • DefaultChallengeScheme: OpenIdConnect
  • ResponseType: code (authorization code flow)
  • UsePkce: true
  • SaveTokens: true
  • GetClaimsFromUserInfoEndpoint: true
  • NameClaimType: "name" (avoids the WS-Fed claim URI mapping)
  • JsonWebTokenHandler.DefaultInboundClaimTypeMap is cleared so claim names match the IdP's JSON names

Accessing tokens from Blazor components

@inject IHttpContextAccessor HttpContextAccessor

@code {
    private async Task<string> GetAccessToken()
    {
        return await HttpContextAccessor.HttpContext
            .GetTokenAsync("access_token");
    }

    private async Task<string> GetIdToken()
    {
        return await HttpContextAccessor.HttpContext
            .GetTokenAsync("id_token");
    }
}

Note: IHttpContextAccessor is registered automatically by the bootstrapper.

Reading user claims

@inject AuthenticationStateProvider AuthStateProvider

@code {
    private string _userName;

    protected override async Task OnInitializedAsync()
    {
        var state = await AuthStateProvider.GetAuthenticationStateAsync();
        _userName = state.User.FindFirst("name")?.Value;
    }
}

Security Headers

Enable via AddSecurityHeaderSupport = true. The OpenIDConnectSettings.Authority value must be configured — it is used to build the form-action CSP directive so the browser can submit to the identity provider.

What is applied

Header Value
X-Frame-Options DENY
X-Content-Type-Options nosniff
Referrer-Policy strict-origin-when-cross-origin
Cross-Origin-Opener-Policy same-origin
Cross-Origin-Resource-Policy same-origin
Cross-Origin-Embedder-Policy require-corp
Content-Security-Policy See below
Permissions-Policy Secure defaults
Server Removed
Strict-Transport-Security max-age=31536000; includeSubDomains (Production only)

Content Security Policy

object-src 'none';
block-all-mixed-content;
img-src 'self' data:;
form-action 'self' https://identity.example.com;
font-src 'self';
base-uri 'self';
frame-ancestors 'none';
style-src 'unsafe-inline' 'self';
script-src 'nonce-{random}' 'unsafe-inline';

Scripts use a per-request nonce. 'unsafe-inline' is retained as a fallback for browsers that do not support nonces.

Tag helper for nonces

Use the NetEscapades.AspNetCore.SecurityHeaders.TagHelpers package in _Host.cshtml:

<script add-nonce="true" src="/_framework/blazor.server.js"></script>

Development vs Production

In Development the Strict-Transport-Security header is omitted. All other headers are applied in both environments.


Authorization

Global authorization (automatic when auth is enabled)

All Razor Pages require an authenticated user:

// Applied automatically by the bootstrapper:
services.AddRazorPages().AddMvcOptions(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

The Blazor hub also requires authorization:

endpoints.MapBlazorHub().RequireAuthorization();

Per-component authorization

@page "/admin"
@attribute [Authorize(Roles = "admin")]

<h1>Admin Dashboard</h1>

AuthorizeView in templates

<AuthorizeView>
    <Authorized>
        <p>Welcome, @context.User.Identity.Name!</p>
    </Authorized>
    <NotAuthorized>
        <p><a href="/login">Please sign in</a></p>
    </NotAuthorized>
</AuthorizeView>

Custom authorization policies

public override void ConfigureServices(IServiceCollection services)
{
    base.ConfigureServices(services);

    services.AddAuthorization(options =>
    {
        options.AddPolicy("AdminOnly", policy =>
            policy.RequireClaim("role", "admin"));

        options.AddPolicy("TenantAccess", policy =>
            policy.RequireClaim("tenant_id"));
    });
}

Razor Pages and MVC Controllers alongside Blazor

Razor Pages

Razor Pages are always registered. They serve as the application shell (e.g., _Host.cshtml) and can be used for login/logout redirect pages.

MVC Controllers

Enable with AddControllersWithViews = true:

{
  "BlazorServerStartupOptions": {
    "AddControllersWithViews": true
  }
}

When authentication is also enabled, AutoValidateAntiforgeryTokenAttribute is applied globally to all controller actions.

Controller endpoints are mapped via endpoints.MapControllers().


Project Layout

MyBlazorApp/
├── Pages/
│   ├── _Host.cshtml          # Application shell (required)
│   ├── _Layout.cshtml
│   ├── Index.razor
│   └── Counter.razor
├── Shared/
│   ├── MainLayout.razor
│   └── NavMenu.razor
├── wwwroot/
│   ├── css/
│   └── js/
├── Program.cs
├── Startup.cs
└── appsettings.json

Environment-Specific Behavior

Behavior Development Production
Exception page Detailed developer page HSTS only
HSTS No Yes
HTTPS redirect If ForceHttps = true If ForceHttps = true
CORS Permissive (any origin/method/header) Not configured
HSTS Strict-Transport-Security Not sent Included in security headers

Extending with Indiko Blocks

Blocks are resolved from the configuration and participate in the full lifecycle:

Hook Called in
ConfigureBuilder(IHostBuilder) CreateHostBuilder — before the host is built
ConfigureServices(IServiceCollection) BlazorServerStartup.ConfigureServices
Configure(IApplicationBuilder, ...) BlazorServerStartup.Configure — after all standard middleware
PreRunAsync(IServiceProvider) BuildHost — after the host is built, before RunAsync
public override void ConfigureServices(IServiceCollection services)
{
    base.ConfigureServices(services); // blocks run here
    // additional registrations
}

Best Practices

  • Keep ClientSecret out of source control — use environment variables, Azure Key Vault, or ASP.NET Core's Secret Manager.
  • Enable ForceHttps and AddSecurityHeaderSupport together in Production.
  • Set EnableForwardedHeaderOptions = true whenever the application runs behind a reverse proxy (nginx, Traefik, Azure Application Gateway, etc.).
  • Do not enable CrossOriginEmbedderPolicy (COEP require-corp) in Development if you use Blazor hot reload, as it blocks cross-origin resources needed by the tooling.
  • Call base.ConfigureServices(services) and base.Configure(app, environment, logger) from your overrides to retain all default wiring.

Target Framework

.NET 10

License

MIT — see LICENSE in the repository root.

Package Description
Indiko.Hosting.Abstractions Core hosting abstractions and base bootstrapper
Indiko.Hosting.Gateway API Gateway hosting with Ocelot and Consul
Indiko.Blocks.Security.Authentication.ASPNetCore Additional authentication blocks
Indiko.Blocks.Security.AuthenticationProvider.Blazor Blazor-specific authentication providers
Indiko.Blocks.Logging.Serilog Structured logging block
Indiko.Blocks.Tracing.OpenTelemetry Distributed tracing block
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.7.1 0 4/23/2026
2.7.0 0 4/23/2026
2.6.4 65 4/21/2026
2.6.2 75 4/21/2026
2.6.1 84 4/18/2026
2.6.0 82 4/17/2026
2.5.1 88 4/14/2026
2.5.0 104 3/30/2026
2.2.18 115 3/8/2026
2.2.17 85 3/8/2026
2.2.16 90 3/8/2026
2.2.15 94 3/7/2026
2.2.13 89 3/7/2026
2.2.12 92 3/7/2026
2.2.10 88 3/6/2026
2.2.9 90 3/6/2026
2.2.8 85 3/6/2026
2.2.7 91 3/6/2026
2.2.5 95 3/6/2026
Loading failed