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
<PackageReference Include="Indiko.Hosting.BlazorServer" Version="2.7.1" />
<PackageVersion Include="Indiko.Hosting.BlazorServer" Version="2.7.1" />
<PackageReference Include="Indiko.Hosting.BlazorServer" />
paket add Indiko.Hosting.BlazorServer --version 2.7.1
#r "nuget: Indiko.Hosting.BlazorServer, 2.7.1"
#:package Indiko.Hosting.BlazorServer@2.7.1
#addin nuget:?package=Indiko.Hosting.BlazorServer&version=2.7.1
#tool nuget:?package=Indiko.Hosting.BlazorServer&version=2.7.1
Indiko.Hosting.BlazorServer
A complete Blazor Server hosting solution with built-in OpenID Connect authentication, PKCE support, security headers, and seamless Indiko Blocks integration.
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, andPreRunAsynclifecycle hooks - Flexible host builder —
ConfigureHostBuilder(...)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.
Approach A: appsettings.json (recommended)
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, theappsettings.jsonvalue 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: CookieDefaultChallengeScheme: OpenIdConnectResponseType:code(authorization code flow)UsePkce:trueSaveTokens:trueGetClaimsFromUserInfoEndpoint:trueNameClaimType:"name"(avoids the WS-Fed claim URI mapping)JsonWebTokenHandler.DefaultInboundClaimTypeMapis 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:
IHttpContextAccessoris 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
ClientSecretout of source control — use environment variables, Azure Key Vault, or ASP.NET Core's Secret Manager. - Enable
ForceHttpsandAddSecurityHeaderSupporttogether in Production. - Set
EnableForwardedHeaderOptions = truewhenever the application runs behind a reverse proxy (nginx, Traefik, Azure Application Gateway, etc.). - Do not enable
CrossOriginEmbedderPolicy(COEPrequire-corp) in Development if you use Blazor hot reload, as it blocks cross-origin resources needed by the tooling. - Call
base.ConfigureServices(services)andbase.Configure(app, environment, logger)from your overrides to retain all default wiring.
Target Framework
.NET 10
License
MIT — see LICENSE in the repository root.
Related Packages
| 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 | Versions 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. |
-
net10.0
- Asp.Versioning.Mvc (>= 8.1.1)
- Asp.Versioning.Mvc.ApiExplorer (>= 8.1.1)
- Indiko.Hosting.Abstractions (>= 2.7.1)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 10.0.6)
- Microsoft.AspNetCore.Razor.Language (>= 6.0.36)
- Microsoft.AspNetCore.WebUtilities (>= 10.0.6)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.6)
- Microsoft.Extensions.DependencyModel (>= 10.0.6)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 8.17.0)
- NetEscapades.AspNetCore.SecurityHeaders (>= 1.3.1)
- NetEscapades.AspNetCore.SecurityHeaders.TagHelpers (>= 1.3.1)
- System.IdentityModel.Tokens.Jwt (>= 8.17.0)
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 |