Loading...
} else { @foreach (var item in items) {@item.Value
} } @code { private Data[]? items; protected override async Task OnInitializedAsync() { items = await DataAccessor.GetData(); } } ``` ## See Also [Section titled “See Also”](#see-also) [Embedded (Local) APIs](/bff/fundamentals/apis/local/)Full reference for BFF-hosted endpoints [Proxying Remote APIs](/bff/fundamentals/apis/remote/)Direct forwarding to upstream services [YARP Integration](/bff/fundamentals/apis/yarp/)Advanced reverse proxy configuration [Rendering Modes & BFF](/bff/fundamentals/blazor/rendering-modes/)Which Blazor modes need BFF [Getting Started: Blazor](/bff/getting-started/blazor/)Full setup walkthrough ----- # Blazor Rendering Modes & BFF > Learn which Blazor rendering modes are compatible with the BFF security pattern and why. Blazor supports [several rendering modes](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0#render-modes). The BFF pattern is only applicable to modes where code runs in the browser (client context), because that is where the risk of token exposure exists. ## Rendering Mode Compatibility [Section titled “Rendering Mode Compatibility”](#rendering-mode-compatibility) | Mode | Description | Renders In | Interactive | Use BFF? | | --------------------------- | ------------------------------------------------------------- | ---------------- | ----------- | -------- | | **Static Server** | Static server-side rendering (SSR) | Server | ❌ | ❌ | | **Interactive Server** | Interactive SSR using Blazor Server and WebSockets | Server | ✅ | ❌ | | **Interactive WebAssembly** | Client-side rendering (CSR) using Blazor WASM | Browser | ✅ | ✅ | | **Interactive Auto** | Starts as Interactive Server, switches to WASM after download | Server → Browser | ✅ | ✅ | ## Static Server [Section titled “Static Server”](#static-server) Caution BFF is not necessary for Static Server rendering. Standard ASP.NET Core authentication patterns apply. Static Server renders Blazor components as plain HTML with no client-side interactivity. Because all rendering happens on the server, tokens never reach the browser. Use standard ASP.NET Core cookie authentication instead of BFF. You may still want to use the `AuthenticationStateProvider` for accessing user claims in components. ## Interactive Server [Section titled “Interactive Server”](#interactive-server) Caution BFF is not typically necessary for Interactive Server rendering. All component interactivity is managed server-side via WebSockets (SignalR). In Interactive Server mode, Blazor components run on the server and push UI updates to the browser over a WebSocket connection. Because no application code runs in the browser, tokens remain server-side naturally. You can still use [Session Management](/bff/fundamentals/session/) features of BFF if you want server-side session control, but the BFF security pattern itself is not required. ## Interactive WebAssembly [Section titled “Interactive WebAssembly”](#interactive-webassembly) Note **BFF is recommended for Interactive WebAssembly.** Your Blazor components execute inside the browser and can be subject to XSS and token theft attacks. In Interactive WebAssembly mode, the Blazor runtime and your application code are downloaded to and executed in the browser. This means: * Your components run in the same JavaScript sandbox as the rest of the page * Any access token stored in the WASM memory is potentially accessible to injected scripts * You must never expose access tokens to WASM components The BFF pattern solves this by keeping tokens on the server. WASM components call BFF-hosted API endpoints (using the authentication cookie), and the BFF attaches the access token server-side before forwarding to remote APIs. See the [Getting Started: Blazor guide](/bff/getting-started/blazor/) for setup instructions. ## Interactive Auto [Section titled “Interactive Auto”](#interactive-auto) Note **BFF is recommended for Interactive Auto.** This mode starts as Interactive Server but transitions to WebAssembly, creating an unpredictable execution context. Interactive Auto combines Interactive Server and Interactive WebAssembly: rendering starts on the server but switches to client-side WASM on subsequent visits after the Blazor bundle is downloaded. Because your application may be running in the browser at any time, you cannot rely on server-side-only token handling. The BFF pattern ensures tokens remain server-side regardless of which rendering mode is active. ## Authentication State [Section titled “Authentication State”](#authentication-state) The `AuthenticationState` contains information about the currently logged-in user, including management claims like the logout URL. Blazor uses `AuthenticationStateProvider` implementations to make authentication state available to components: * **On the server**: The BFF’s `AddServerManagementClaimsTransform` enriches the claims with the logout URL. * **On the client (WASM)**: The `BffClientAuthenticationStateProvider` polls `/bff/user` to keep the client in sync with the server session. This also notifies the frontend if the session is terminated server-side (e.g., back-channel logout). ## Server-Side Token Store [Section titled “Server-Side Token Store”](#server-side-token-store) Blazor Server applications stream content over a WebSocket, so there is often no `HttpContext` available during component execution. This means: * You cannot use `HttpContext` extension methods in Blazor Server components * The normal mechanism to attach tokens to `HttpClient` calls does not work without special setup When you register `AddBlazorServer()`, BFF automatically registers the `ServerSideTokenStore` and Duende.AccessTokenManagement integration so that token management works correctly in Blazor Server. For more details, see [Blazor Server token management](/accesstokenmanagement/blazor-server/). ## See Also [Section titled “See Also”](#see-also) [Data Access Patterns](/bff/fundamentals/blazor/data-access/)How to call APIs from Blazor components [Getting Started: Blazor](/bff/getting-started/blazor/)Full walkthrough setup guide [Troubleshooting](/bff/troubleshooting/)Common Blazor BFF issues ----- # Production Deployment > Guide for deploying Duende BFF to production, covering load balancing, data protection, health checks, cookie domain configuration, and monitoring. This page covers the production-specific concerns you need to address before deploying a BFF host. For middleware pipeline order, see [Middleware Pipeline](/bff/fundamentals/middleware-pipeline/). ## Load Balancing and Sticky Sessions [Section titled “Load Balancing and Sticky Sessions”](#load-balancing-and-sticky-sessions) The BFF uses ASP.NET Core’s Data Protection to encrypt and sign session cookies. In a multi-instance (load-balanced) deployment, **all instances must share the same Data Protection key ring** — otherwise cookies issued by one instance cannot be decrypted by another, causing random logout on failover. ### Shared Key Storage [Section titled “Shared Key Storage”](#shared-key-storage) Configure Data Protection to store keys in a shared location accessible to all instances: ```csharp // Using Azure Blob Storage + Azure Key Vault builder.Services.AddDataProtection() .PersistKeysToAzureBlobStorage(connectionString, "data-protection", "keys.xml") .ProtectKeysWithAzureKeyVault(keyIdentifier, credential); // Using a network file share or a database builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\dp-keys")) .ProtectKeysWithCertificate(certificate); ``` Do not use in-memory keys in production The default in-memory key ring is regenerated on every restart. Any existing sessions are invalidated when the process restarts or when traffic is routed to a new instance. See also: [Data Protection](/general/data-protection/) ### Server-Side Sessions (Recommended for Multi-Instance) [Section titled “Server-Side Sessions (Recommended for Multi-Instance)”](#server-side-sessions-recommended-for-multi-instance) With cookie-only sessions, every instance must share Data Protection keys. With **server-side sessions**, the cookie only holds an opaque session ID — the session payload is stored in a shared database. This is simpler to operate because: * Key ring only needs to be consistent (not necessarily shared) — the cookie just holds an ID * Sessions can be inspected and revoked server-side * Cookie size is minimized [Server-Side Sessions](/bff/fundamentals/session/server-side-sessions/)Setup guide for database-backed session storage ### Sticky Sessions [Section titled “Sticky Sessions”](#sticky-sessions) If you cannot use server-side sessions and cannot share a Data Protection key ring, configure your load balancer to route each user consistently to the same instance (“sticky sessions” / session affinity). This is a last resort — prefer shared key storage. ## Health Check Endpoints [Section titled “Health Check Endpoints”](#health-check-endpoints) Expose a health check endpoint so your load balancer and orchestrator (Kubernetes, etc.) can detect unhealthy instances: ```csharp builder.Services.AddHealthChecks(); // In your pipeline (after UseRouting): app.MapHealthChecks("/health"); ``` For a more complete health check that validates downstream dependencies (database, token endpoint reachability): ```csharp builder.Services.AddHealthChecks() .AddDbContextCheckYou (@context.User.Identity?.Name) are not authorized to access this resource.
}This component demonstrates showing data.
@if (forecasts == null) {Loading...
} else {| Date | Temp. (C) | Temp. (F) | Summary |
|---|---|---|---|
| @forecast.Date.ToShortDateString() | @forecast.TemperatureC | @forecast.TemperatureF | @forecast.Summary |