Skip to content

Commit 352339f

Browse files
Erwinvandervalkmaartenba
authored andcommitted
BFF v4 multi-frontend documentation
1 parent 6c09a53 commit 352339f

File tree

6 files changed

+647
-11
lines changed

6 files changed

+647
-11
lines changed

src/content/docs/bff/fundamentals/index.md

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
label: "Multiple frontends"
22
collapsed: true
3-
order: 120
3+
order: 120
4+
badge:
5+
text: v4
6+
variant: tip
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
title: "BFF Configuration"
3+
description: Documentation for managing BFF configuration
4+
sidebar:
5+
order: 3
6+
label: "Configuration"
7+
8+
---
9+
It's possible to configure the BFF via IConfiguration.
10+
11+
```csharp {6}
12+
13+
var bffConfig = new ConfigurationBuilder()
14+
.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "BffConfig.json"), optional: false, reloadOnChange: true)
15+
16+
services
17+
.AddBff()
18+
.LoadConfiguration(bffConfig);
19+
20+
```
21+
22+
The configuration supports dynamic reloading (so any new frontend added / removed is immediately reflected).
23+
24+
### BffConfiguration
25+
26+
- **defaultOidcSettings**
27+
OIDC settings applied globally to all frontends unless overridden.
28+
Type: OidcConfiguration object (see below for properties).
29+
30+
- **defaultCookieSettings**
31+
Cookie settings applied globally to all frontends unless overridden.
32+
Type: CookieConfiguration object (properties depend on your implementation).
33+
34+
- **frontends**
35+
Dictionary of frontend configurations.
36+
Each key is a frontend name, and the value is a BffFrontendConfiguration object (see below).
37+
38+
---
39+
40+
### BffFrontendConfiguration JSON Properties
41+
42+
- **indexHtmlUrl**
43+
The URL to the main HTML file for this frontend.
44+
Example: `"https://localhost:5005/static/index.html"`
45+
46+
- **matchingPath**
47+
The path prefix for requests routed to this frontend.
48+
Example: `"/from-config"`
49+
50+
- **matchingOrigin**
51+
The origin to match for this frontend.
52+
Example: `"https://localhost:5005"`
53+
54+
- **oidc**
55+
OIDC settings specific to this frontend.
56+
Type: OidcConfiguration object (see below).
57+
58+
- **cookies**
59+
Cookie settings specific to this frontend.
60+
Type: CookieConfiguration object (see below)
61+
62+
- **RemoteApis**
63+
Remote api's for this frontend. (see below)
64+
65+
### RemoteApiConfiguration JSON Properties
66+
67+
- **localPath**
68+
String. The local path that will be used to access the remote API.
69+
Example: `"/api/user-token"`
70+
71+
- **targetUri**
72+
String. The target URI of the remote API.
73+
Example: `"https://localhost:5010"`
74+
75+
- **requiredTokenType**
76+
String. The token requirement for accessing the remote API.
77+
Possible values: `"User"`, `"Client"`, `"None"`, `"OptionalUserOrClient"`, `"OptionalUserOrNone"`
78+
Default: `"User"`
79+
80+
- **tokenRetrieverTypeName**
81+
String. The type name of the access token retriever to use for this remote API.
82+
83+
- **userAccessTokenParameters**
84+
Object. Parameters for retrieving a user access token (see below).
85+
86+
- **activityTimeout**
87+
String. How long a request is allowed to remain idle between operations before being canceled.
88+
Use C# `TimeSpan` serialization format, e.g. `"00:01:40"` for 100 seconds.
89+
90+
- **allowResponseBuffering**
91+
Boolean. Allows write buffering when sending a response back to the client (if supported by the server).
92+
Note: Enabling this can break server-sent events (SSE) scenarios.
93+
94+
---
95+
96+
### UserAccessTokenParameters JSON Properties
97+
98+
- **signInScheme**
99+
String. The scheme used for signing in the user (typically the cookie authentication scheme).
100+
Example: `"Cookies"`
101+
102+
- **challengeScheme**
103+
String. The authentication scheme to be used for challenges.
104+
Example: `"OpenIdConnect"`
105+
106+
- **forceRenewal**
107+
Boolean. Whether to force renewal of the access token.
108+
109+
- **resource**
110+
String. The resource for which the access token is requested.
111+
Example: `"https://api.example.com"`
112+
113+
114+
### OidcConfiguration JSON Properties
115+
116+
- **clientId**
117+
The client ID of the OpenID Connect client.
118+
119+
- **clientSecret**
120+
The client secret of the OpenID Connect client.
121+
122+
- **callbackPath**
123+
The path or URI to which the OpenID Connect client will redirect after authentication.
124+
125+
- **authority**
126+
The authority URI, typically the issuer or identity provider endpoint.
127+
128+
- **responseType**
129+
The response type that the OpenID Connect client will request.
130+
131+
- **responseMode**
132+
The response mode that the OpenID Connect client will use to return the authentication response.
133+
134+
- **mapInboundClaims**
135+
Boolean. Whether to map inbound claims from the OpenID Connect provider to the user's claims in the application.
136+
137+
- **saveTokens**
138+
Boolean. Whether to save the tokens received from the OpenID Connect provider.
139+
140+
- **scope**
141+
Array of strings. The scopes that the OpenID Connect client will request from the provider.
142+
143+
- **getClaimsFromUserInfoEndpoint**
144+
Boolean. Whether to retrieve claims from the UserInfo endpoint of the OpenID Connect provider.
145+
146+
### CookieConfiguration JSON Properties
147+
148+
- **httpOnly**
149+
Boolean. Indicates whether the cookie is inaccessible by client-side script. Defaults to true.
150+
151+
- **sameSite**
152+
String. The SameSite attribute of the cookie. Defaults to strictg.
153+
Possible values: `"None"`, `"Lax"`, `"Strict"`
154+
155+
- **securePolicy**
156+
String. The policy used to determine if the cookie is sent only over HTTPS.
157+
Possible values: `"Always"`, `"None"`, `"SameAsRequest"`
158+
159+
- **name**
160+
String. The name of the cookie.
161+
162+
- **maxAge**
163+
String. The max-age for the cookie.
164+
Example: "0:01:00 for 1 minute
165+
166+
- **path**
167+
String. The cookie path. The BFF will configure the default values for this property.
168+
Example: `"/"`
169+
170+
- **domain**
171+
String. The domain to associate the cookie with. The BFF will configure the default values for this property.
172+
Example: `"example.com"`
173+
174+
### Example
175+
176+
```json
177+
{
178+
"defaultOidcSettings": {
179+
"clientId": "global-client",
180+
"authority": "https://login.example.com"
181+
},
182+
"defaultCookieSettings": null,
183+
"frontends": {
184+
"some_frontend": {
185+
"indexHtmlUrl": "https://localhost:5005/static/index.html",
186+
"matchingPath": "/from-config",
187+
"oidc": {
188+
"clientId": "frontend1-client",
189+
"scope": ["openid", "profile", "email"]
190+
}
191+
}
192+
}
193+
}

src/content/docs/bff/fundamentals/multi-frontend/index.mdx

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,100 @@ sidebar:
77

88
---
99

10-
asdf
10+
The Backend For Frontend pattern basically states that there should
11+
be a single backend for each frontend. While for some applications / architectures this
12+
makes a lot of sense, because there is a 1-to-1 mapping between the api surface
13+
and the browser based application, for some other architectures this may not be useful.
14+
15+
Especially in micro-service based architectures, where there are many backend api's
16+
and multiple frontends using these apis, having a dedicated backend service for each frontend
17+
introduces quite a lot of operational overhead.
18+
19+
To overcome this issue, a single BFF instance can support multiple frontends. Each frontend you configure can:
20+
* Define it's own OpenID Connect configuration
21+
* Define it's own Cookie settings
22+
* Define it's own api surface
23+
* Be identified either via path based routing and/or origin selection.
24+
25+
Adding additional frontends to the BFF has very little impact on the performance on the BFF itself, but keep in mind
26+
that the traffic for all the frontends is proxied through the bff.
27+
28+
## Frontend selection
29+
30+
Each request to a frontend has to be uniquely defined by either it's path, it's origin or a combination of the two.
31+
If you specify neither, then it's considered the default frontend.
32+
33+
Frontends are matched using the following algorithm:
34+
35+
1. **Selection by both origin and path:** If there is a frontend that matches both the origin AND has the most specific match to a path, then it's selected.
36+
2. **Selection by origin only:** Then if there is a frontend with only origins configured and it matches the path, then it's selected.
37+
3. **Selection by path only:** Then if there is a frontend with a matching path specified, then it's selected.
38+
4. **Default frontend:** Then if there is a default frontend configured, then it's selected.
39+
40+
Basically, the most specific match will be selected.
41+
42+
:::note
43+
When using path based routing, then the frontend's path is added to the [PathBase](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequest.pathbase)
44+
and removed from the [Path](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequest.path). This means that any routing
45+
that happens in the application is relative to the path of the frontend. This also includes the openid callback paths.
46+
:::
47+
48+
## Adding a frontend during startup
49+
50+
The simplest way to add frontends is during startup.
51+
52+
```csharp {3}
53+
services
54+
.AddBff()
55+
.WithFrontends(new BffFrontend(BffFrontendName.Parse("frontend1")));
56+
```
57+
You can call WithFrontends with multiple frontends in one go, or call it multiple times.
58+
59+
## Adding / updating a frontend dynamically at runtime
60+
61+
If you want to manipulate the frontends at runtime, you can do so via the IFrontendCollection interface.
62+
63+
```csharp
64+
var frontends = app.Services.GetRequiredService<IFrontendCollection>();
65+
66+
frontends.AddOrUpdate(new BffFrontend(name));
67+
68+
frontends.Remove(name);
69+
```
70+
71+
## Defining the api surface
72+
73+
A frontend can define it's own api surface, by specifying remote api's.
74+
75+
```csharp
76+
77+
var frontend = new BffFrontend(BffFrontendName.Parse("frontend1"))
78+
.WithRemoteApis(
79+
// map the local path /path to the remote api
80+
new RemoteApi(LocalPath.Parse("/some_path"), new Uri("https://remote-api")))
81+
82+
// You can also configure various options, such as the type of token,
83+
// retrieval parameters, etc..
84+
new RemoteApi(LocalPath.Parse("/with_options"), new Uri("https://remote-api")))
85+
.WithAccessToken(RequiredTokenType.UserOrClient),
86+
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>(),
87+
.WithUserAccessTokenParameters(new BffUserAccessTokenParameters { Resource = Resource.Parse("urn:isolated-api") }));
88+
```
89+
90+
See the topic on [Token Management](../tokens.md) for more information about the various token management options.
91+
92+
## Index HTML proxying
93+
94+
When deploying a multi-frontend bff, it makes most sense to have the frontend's configured with an
95+
Index.HTML file that's retrieved from a CDN.
96+
97+
```csharp
98+
99+
var frontend = new BffFrontend(BffFrontendName.Parse("frontend1"))
100+
.WithIndexHtml(new Uri("https://my_cdn/some_app/index.html"))
101+
```
102+
103+
When you do this, the BFF automatically wires up a catch-all route that serves the index.html for that specific frontend.
104+
See [Serve the index page from the BFF host](../../architecture/ui-hosting.md#serve-the-index-page-from-the-bff-host) for more information.
105+
106+

src/content/docs/bff/fundamentals/options.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ builder.Services.AddBff(options =>
4242

4343
The ASP.NET environment names that enable the diagnostics endpoint. Defaults to "Development".
4444

45+
* ***BackChannelHttpHandler***
46+
A HTTP message handler that's used to configure backchannel communication. Typically used during testing. Configuring this will automatically configure the BackChannelHttpHandler property in _OpenIDConnectOptions_ and also set it as the primary http message handler for retrieving the index.html.
47+
48+
* ***AutomaticallyRegisterBffMiddleware*** (added in 4.0)
49+
When applying BFF V4 multiple frontends, a lot of middlewares get automatically added to the pipeline. For example, the frontend selection middleware, the authentication handlers, etc. If you don't want this automatic behavior, then you can turn it off and register these middlewares manually.
50+
51+
* ***IndexHtmlClientName***
52+
If BFF is configured to automatically retrieve the index.html, then it needs a http client to do so. With this name you can automatically configure http client in the http client factory.
53+
54+
* ***AllowedSilentLoginReferers***
55+
For silent login to work, you normally need to have the BFF backend and the frontend on the same origin. If you have a split host scenario, meaning the backend on a different origin (but same site) as the frontend, then you can use the referer header to differentiate which browser window to post the silent login results to. This array must then contain the list of allowed referer header values.
56+
4557
## Paths
4658

4759
* ***LoginPath***
@@ -95,12 +107,14 @@ builder.Services.AddBff(options =>
95107
If *true*, all sessions for the subject will be revoked. If false, just the specific session will be revoked.
96108
Defaults to *false*.
97109

98-
* ***EnableSessionCleanup***
110+
* ***~~EnableSessionCleanup~~*** (removed in V4)
99111

100112
Indicates if expired server side sessions should be cleaned up.
101113
This requires an implementation of IUserSessionStoreCleanup to be registered in the ASP.NET Core service provider.
102114
Defaults to *false*.
103115

116+
In V4, you need to opt into this value by calling **.AddSessionCleanupBackgroundProcess()**
117+
104118
* ***SessionCleanupInterval***
105119

106120
Interval at which expired sessions are cleaned up.
@@ -129,6 +143,9 @@ builder.Services.AddBff(options =>
129143
a new Access Token fails. This behavior is only triggered when proxying requests to remote
130144
APIs with TokenType.User or TokenType.UserOrClient. Defaults to True.
131145

146+
* ***DisableAntiForgeryCheck*** (added in V4)
147+
A delegate that determines if the anti-forgery check should be disabled for a given request. The default is not to disable anti-forgery checks.
148+
132149

133150
# BFF Blazor Server Options
134151

0 commit comments

Comments
 (0)