|
| 1 | +--- |
| 2 | +title: "Architecture" |
| 3 | +description: Overview of BFF host architecture, including authentication, session management, and integration with ASP.NET Core components |
| 4 | +date: 2020-09-10T08:22:12+02:00 |
| 5 | +sidebar: |
| 6 | + order: 1 |
| 7 | + label: "Overview" |
| 8 | +redirect_from: |
| 9 | + - /bff/v2/architecture/ |
| 10 | + - /bff/v3/architecture/ |
| 11 | + - /identityserver/v5/bff/architecture/ |
| 12 | + - /identityserver/v6/bff/architecture/ |
| 13 | + - /identityserver/v7/bff/architecture/ |
| 14 | +--- |
| 15 | + |
| 16 | +import { CardGrid, LinkCard } from "@astrojs/starlight/components"; |
| 17 | + |
| 18 | +A BFF host is an ASP.NET Core application that acts as a security proxy between the browser and your backend APIs. Understanding the key architectural decisions up front will save you significant rework later. |
| 19 | + |
| 20 | +:::tip[New to BFF?] |
| 21 | +If you haven't yet decided whether to use BFF, start with the [overview](/bff/) which covers the threat model and the BFF-vs-token-in-browser comparison. |
| 22 | +::: |
| 23 | + |
| 24 | +## How the BFF Fits Into Your System |
| 25 | + |
| 26 | +The following diagram shows how the BFF protects browser-based applications: |
| 27 | + |
| 28 | +```mermaid |
| 29 | +flowchart TD |
| 30 | + subgraph Browser |
| 31 | + SPA["Browser-Based Application"] |
| 32 | + CookieJar["🍪 Cookie Jar"] |
| 33 | + end |
| 34 | +
|
| 35 | + subgraph BFF["BFF Host"] |
| 36 | + AuthEndpoints["Authentication<br/>Endpoints"] |
| 37 | + SessionMgmt["Session<br/>Management"] |
| 38 | + CookieAuth["Cookie Authorization"] |
| 39 | + CSRF["CSRF Protection"] |
| 40 | + Proxy["Proxy to<br/>External APIs"] |
| 41 | + LocalAPIs["Local APIs"] |
| 42 | + SessionStore[("Server-Side<br/>Session Storage")] |
| 43 | + end |
| 44 | +
|
| 45 | + IdP["Identity Provider"] |
| 46 | + ExternalAPIs["External APIs"] |
| 47 | +
|
| 48 | + SPA -->|"login / logout"| AuthEndpoints |
| 49 | + AuthEndpoints -->|"Set-Cookie"| CookieJar |
| 50 | + CookieJar -->|"Auth cookie"| CookieAuth |
| 51 | + AuthEndpoints <-->|"redirect"| IdP |
| 52 | + AuthEndpoints --> SessionMgmt |
| 53 | + SessionMgmt --> SessionStore |
| 54 | + CookieAuth --> CSRF |
| 55 | + CSRF --> Proxy |
| 56 | + CSRF --> LocalAPIs |
| 57 | + Proxy -->|"Bearer token"| ExternalAPIs |
| 58 | + SessionMgmt -->|"Acquire tokens"| IdP |
| 59 | + ExternalAPIs -->|"Validate tokens"| IdP |
| 60 | +``` |
| 61 | + |
| 62 | +The BFF sits between the browser and everything else. The browser only ever holds a **session cookie** — it never sees tokens. The BFF exchanges that cookie for bearer tokens when forwarding requests to downstream APIs. |
| 63 | + |
| 64 | +## Architectural Decisions |
| 65 | + |
| 66 | +### Decision 1: Where Does Your UI Live? |
| 67 | + |
| 68 | +The simplest setup hosts both the UI assets and the BFF from the **same origin**. This makes cookies same-site, eliminates CORS, and avoids [third-party cookie blocking](/bff/architecture/third-party-cookies.md). |
| 69 | + |
| 70 | +You can also run the frontend on a **separate origin** (e.g. a Vite dev server, a CDN) and point it at the BFF via CORS. This is more complex but enables independent deployment. |
| 71 | + |
| 72 | +<LinkCard |
| 73 | + href="/bff/architecture/ui-hosting/" |
| 74 | + title="UI Hosting" |
| 75 | + description="Full comparison of same-origin vs. separate-origin hosting" |
| 76 | +/> |
| 77 | + |
| 78 | +### Decision 2: Cookie-Only vs. Server-Side Sessions |
| 79 | + |
| 80 | +By default, the BFF stores the entire session in the cookie. This is simple and stateless but has limits: cookie size, no server-side revocation. |
| 81 | + |
| 82 | +With **server-side sessions**, the cookie holds only a session ID. The server stores the session state (typically in a database or distributed cache). This enables: |
| 83 | +- Forced logout across all sessions |
| 84 | +- Back-channel logout from the identity provider |
| 85 | +- Querying active sessions |
| 86 | + |
| 87 | +<LinkCard |
| 88 | + href="/bff/fundamentals/session/server-side-sessions/" |
| 89 | + title="Server-Side Sessions" |
| 90 | + description="Configure server-side session storage for scalability and revocation" |
| 91 | +/> |
| 92 | + |
| 93 | +### Decision 3: How Do You Expose APIs? |
| 94 | + |
| 95 | +| API Pattern | When to Use | |
| 96 | +|---|---| |
| 97 | +| **Local API** | Business logic hosted inside the BFF process itself. Lowest latency, no token forwarding needed. | |
| 98 | +| **Remote API (direct)** | External microservice. BFF forwards the request with a bearer token attached. | |
| 99 | +| **Remote API (YARP)** | External microservice with complex routing rules. BFF uses YARP as the reverse proxy. | |
| 100 | + |
| 101 | +<LinkCard |
| 102 | + href="/bff/fundamentals/apis/" |
| 103 | + title="API Types" |
| 104 | + description="Decision flowchart for choosing the right API pattern" |
| 105 | +/> |
| 106 | + |
| 107 | +### Decision 4: Single Frontend vs. Multi-Frontend |
| 108 | + |
| 109 | +Each BFF instance is tied to **one** browser-based application and **one** OIDC client registration. If you have multiple frontends (e.g. a customer portal and an admin app), run separate BFF instances with separate client IDs. They can share infrastructure (same process, different routes) but should not share session state or token storage. |
| 110 | + |
| 111 | +<LinkCard |
| 112 | + href="/bff/fundamentals/options/#common-configurations" |
| 113 | + title="Common Configurations" |
| 114 | + description="Multi-frontend configuration example" |
| 115 | +/> |
| 116 | + |
| 117 | +### Decision 5: Blazor or JavaScript? |
| 118 | + |
| 119 | +Both are supported, but have different integration patterns: |
| 120 | + |
| 121 | +- **JavaScript SPAs** interact with the BFF via `/bff/user`, `/bff/login`, `/bff/logout`, and API endpoints |
| 122 | +- **Blazor** uses built-in `AuthenticationStateProvider` integration and can call APIs server-side (no token forwarding from browser) |
| 123 | + |
| 124 | +<LinkCard |
| 125 | + href="/bff/fundamentals/blazor/" |
| 126 | + title="Blazor Fundamentals" |
| 127 | + description="Blazor-specific guidance for rendering modes, data access, and auth state" |
| 128 | +/> |
| 129 | + |
| 130 | +## Trust Boundaries |
| 131 | + |
| 132 | +```mermaid |
| 133 | +flowchart TD |
| 134 | + subgraph Browser["Browser (untrusted)"] |
| 135 | + B1["Holds session cookie only<br/>(HttpOnly, Secure, SameSite)"] |
| 136 | + B2["Never sees access or refresh tokens"] |
| 137 | + end |
| 138 | +
|
| 139 | + subgraph BFF["BFF Host (trusted server)"] |
| 140 | + BFF1["Validates session cookie on every request"] |
| 141 | + BFF2["Manages access/refresh tokens in server memory or DB"] |
| 142 | + BFF3["Enforces anti-forgery (X-CSRF header) on API routes"] |
| 143 | + end |
| 144 | +
|
| 145 | + subgraph IdP["Identity Provider<br/>(e.g. IdentityServer)"] |
| 146 | + end |
| 147 | +
|
| 148 | + subgraph APIs["Downstream APIs<br/>(microservices, external)"] |
| 149 | + end |
| 150 | +
|
| 151 | + Browser -->|"HTTPS + Cookie"| BFF |
| 152 | + BFF -->|"OIDC/OAuth (HTTPS)"| IdP |
| 153 | + BFF -->|"Bearer token (HTTPS)"| APIs |
| 154 | +``` |
| 155 | + |
| 156 | +The critical security property: **tokens never cross the trust boundary into the browser**. All token operations happen server-to-server. |
| 157 | + |
| 158 | +## Internals |
| 159 | + |
| 160 | +Duende.BFF is built on top of: |
| 161 | + |
| 162 | +| Component | Role | Details | |
| 163 | +|---|---|---| |
| 164 | +| ASP.NET OIDC handler | Protocol processing (auth code + PKCE, token exchange) | Standard ASP.NET middleware | |
| 165 | +| ASP.NET Cookie handler | Session management and cookie issuance | Extended by BFF for server-side sessions | |
| 166 | +| Duende.AccessTokenManagement | Token storage, refresh, revocation | [Docs](/accesstokenmanagement/index.mdx) | |
| 167 | +| YARP | Reverse proxy for remote APIs | [BFF YARP integration](/bff/fundamentals/apis/yarp.md) | |
| 168 | + |
| 169 | +## See Also |
| 170 | + |
| 171 | +<CardGrid> |
| 172 | + <LinkCard |
| 173 | + href="/identityserver/fundamentals/clients/" |
| 174 | + title="IdentityServer Client Configuration" |
| 175 | + description="Register your BFF as a confidential OIDC client" |
| 176 | + /> |
| 177 | + <LinkCard |
| 178 | + href="/bff/architecture/third-party-cookies/" |
| 179 | + title="Third-Party Cookies" |
| 180 | + description="How browser cookie restrictions affect BFF architecture" |
| 181 | + /> |
| 182 | + <LinkCard |
| 183 | + href="/bff/architecture/ui-hosting/" |
| 184 | + title="UI Hosting" |
| 185 | + description="Options for hosting the frontend alongside the BFF" |
| 186 | + /> |
| 187 | + <LinkCard |
| 188 | + href="/bff/fundamentals/middleware-pipeline/" |
| 189 | + title="Middleware Pipeline" |
| 190 | + description="Canonical middleware order reference" |
| 191 | + /> |
| 192 | +</CardGrid> |
| 193 | + |
0 commit comments