Skip to content

Commit ace98b8

Browse files
authored
Merge pull request #757 from DuendeSoftware/bffv4
BFF v4 documentation spike
2 parents c358320 + ecfacb2 commit ace98b8

File tree

19 files changed

+1210
-206
lines changed

19 files changed

+1210
-206
lines changed

.idea/codeStyles/Project.xml

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/prettier.xml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.mdx
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
title: "Multi-frontend support"
3+
description: Overview on what BFF multi-frontend support is, how it works and why you would use it.
4+
date: 2024-06-11T08:22:12+02:00
5+
sidebar:
6+
label: "Multiple Frontends"
7+
order: 5
8+
badge:
9+
text: v4
10+
variant: tip
11+
---
12+
13+
BFF V4.0 introduces the capability to support multiple BFF Frontends in a single host. This helps to simplify your application landscape by consolidating multiple physical BFF Hosts into a single deployable unit.
14+
15+
A single BFF setup consists of:
16+
1. A browser based application, typically built using technology like React, Angular or VueJS. This is typically deployed to a Content Delivery Network (CDN).
17+
2. A BFF host, that will take care of the OpenID Connect login flows.
18+
3. An API surface, exposed and protected by the BFF.
19+
20+
With the BFF Multi-frontend support, you can logically host multiple of these BFF Setups in a single host. The concept of a single frontend (with OpenID Connect configuration, an API surface and a browser based app) is now codified inside the BFF. By using a flexible frontend selection mechanism (using Origins or Paths to distinguish), it's possible to create very flexible setups.
21+
22+
The BFF dynamically configures the aspnet core authentication pipeline according to recommended practices. For example, when doing Origin based routing, it will configure the cookies using the most secure settings and with the prefix [`__Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie).
23+
24+
Frontends can be added or removed dynamically from the system, without having to restart the system. You can do this via configuration (for example by modifying a configuration file) or programmatically.
25+
26+
:::note
27+
The Duende BFF V4 library doesn't ship with an abstraction to store or read frontends from a database. It's possible to implement this by creating your own store (based on your requirements), then modify the `FrontendCollection` at run-time.
28+
:::
29+
30+
## A Typical Example
31+
32+
Consider an enterprise that hosts multiple browser based applications. Each of these applications is developed by a separate team and as such, has it's own deployment schedule.
33+
34+
There are some internal-facing applications that are exclusively used by internal employees. These internal employees are all present in Microsoft Entra ID, so these internal-facing applications should directly authenticate against Microsoft Entra ID. These applications also use several internal APIs, that due to the sensitivity, should not be accessible by external users. However, they also use some of the more common APIs. These apps are only accessible via an internal DNS name, such as `https://app1.internal.example.com`.
35+
36+
There are also several public facing applications, that are used directly by customers. These users should be able to log in using their own identity, via providers like Google, Twitter, or others. This authentication process is handled by Duende IdentityServer. There is constant development ongoing on these applications and it's not uncommon for new applications to be introduced. There should be single sign-on across all these public facing applications. They are all available on the same domain name, but use path based routing to distinguish themselves, such as `https://app.example.com/app1`
37+
38+
There is also a partner portal. This partner portal can only be accessed by employees of the partners. Each partner should be able to bring their own identity provider. This is implemented using the [Dynamic Providers](/identityserver/ui/login/dynamicproviders/) feature of Duende IdentityServer.
39+
40+
This setup, with multiple frontends, each having different authentication requirements and different API surfaces, is now supported by the BFF.
41+
42+
Each frontend can either rely on the global configuration or override (parts of) this configuration, such as the identity provider or the Client ID and Client Secret to use.
43+
44+
It's also possible to dynamically add or remove frontends, without restarting the BFF host.
45+
46+
## Internals
47+
48+
BFF V4 still allows you to manually configure the ASP.NET Core authentication options, by calling `.AddAuthentication().AddOpenIdConnect().AddCookies()`. However, if you wish to use the multi-frontend features, then this setup needs to become dynamic.
49+
50+
To achieve this, the BFF automatically configures the ASP.NET Core pipeline:
51+
52+
![BFF Multi-Frontend Pipeline](../images/bff_multi_frontend_pipeline.svg)
53+
54+
1. `FrontendSelectionMiddleware` - This middleware performs the frontend selection by seeing which frontend's selection criteria best matches the incoming request route. It's possible to mix both path based routing origin based routing, so the most specific will be selected.
55+
2. `PathMappingMiddleware` - If you use path mapping, in the selected frontend, then it will automatically map the frontend's path so none of the subsequent middlewares know (or need to care) about this fact.
56+
3. `OpenIdCallbackMiddleware` - To dynamically perform the OpenID Connect authentication without explicitly adding each frontend as a scheme, we inject a middleware that will handle the OpenID Connect callbacks. This only kicks in for dynamic frontends.
57+
4. Your own applications logic is executed in this part of the pipeline. For example, calling `.UseAuthentication(), .UseRequestLogging()`, etc.
58+
59+
After your application's logic is executed, there are two middlewares registered as fallback routes:
60+
61+
5. `MapRemoteRoutesMiddleware` - This will handle any configured remote routes. Note, it will not handle plain YARP calls, only routes that are specifically added to a frontend.
62+
63+
6. `ProxyIndexMiddleware` - If configured, this proxy the `index.html` to start the browser based app.
64+
65+

src/content/docs/bff/extensibility/tokens.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ Implementations of the *IAccessTokenRetriever* can be added to endpoints when th
111111

112112
```cs
113113
app.MapRemoteBffApiEndpoint(
114-
"/API/impersonation",
115-
"https://API.example.com/endpoint/requiring/impersonation"
116-
).RequireAccessToken(TokenType.User)
114+
"/api/impersonation",
115+
"https://api.example.com/endpoint/requiring/impersonation"
116+
).WithAccessToken(RequiredTokenType.User)
117117
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>();
118118
```
119119

src/content/docs/bff/fundamentals/apis/remote.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ The `MapRemoteBffApiEndpoint` extension method maps a path and all sub-paths bel
4343

4444
```csharp
4545
// Program.cs
46-
app.MapRemoteBffApiEndpoint("/API/users", "https://remoteHost/users")
47-
.RequireAccessToken(TokenType.User);
46+
app.MapRemoteBffApiEndpoint("/api/users", "https://remoteHost/users")
47+
.WithAccessToken(RequiredTokenType.User);
4848
```
4949

5050
:::note
5151
This example opens up the complete */users* API namespace to the frontend, and thus, to the outside world. While it is convenient to register API paths this way, consider if you need to be more specific hen designing the forwarding paths to prevent accidentally exposing unintended endpoints.
5252
:::
5353

54-
The `RequireAccessToken` method can be added to [specify token requirements](#access-token-requirements) for the remote API. The BFF will automatically forward the correct access token to the remote API, which will be scoped to the client application, the user, or either.
54+
The `WithAccessToken` method can be added to [specify token requirements](#access-token-requirements) for the remote API. The BFF will automatically forward the correct access token to the remote API, which will be scoped to the client application, the user, or either.
5555

5656
## Securing Remote APIs
5757

@@ -81,11 +81,19 @@ The value of the header is not important, but its presence, combined with the co
8181

8282
#### Require authorization
8383

84-
The `MapRemoteBffApiEndpoint` method returns the appropriate type to integrate with the ASP.NET Core authorization system. You can attach authorization policies to remote endpoints using `RequireAuthorization` extension method, just as you would for a standard ASP.NET core endpoint created with `MapGet`. The authorization middleware will then enforce that policy before forwarding requests on that route to the remote endpoint.
84+
The `MapRemoteBffApiEndpoint` method returns the appropriate type to integrate with the ASP.NET Core authorization system. You can attach authorization policies to remote endpoints using the `WithAccessToken` extension method, just as you would for a standard ASP.NET core endpoint created with `MapGet`. The authorization middleware will then enforce that policy before forwarding requests on that route to the remote endpoint.
85+
86+
:::note
87+
In Duende.BFF version 3, use the `MapRemoteBffApiEndpoint` method with the `RequireAuthorization` extension method to attach authorization policies.
88+
:::
8589

8690
#### Access token requirements
8791

88-
Remote APIs sometimes allow anonymous access, but usually require an access token, and the type of access token (user or client) will vary as well. You can specify access token requirements via the `RequireAccessToken` extension method. Its `TokenType` parameter has three options:
92+
Remote APIs sometimes allow anonymous access, but usually require an access token, and the type of access token (user or client) will vary as well. You can specify access token requirements via the `WithAccessToken` extension method. Its `RequiredTokenType` parameter has three options:
93+
94+
* `None`
95+
96+
No token is required.
8997

9098
* `User`
9199

@@ -99,7 +107,9 @@ Remote APIs sometimes allow anonymous access, but usually require an access toke
99107

100108
Either a valid user access token or a valid client access token (as fallback) is required and will be forwarded to the remote API.
101109

102-
You can also use the `WithOptionalUserAccessToken` extension method to specify that the API should be called with a user access token if one is available and anonymously if not.
110+
* `UserOrNone`
111+
112+
A valid user access token will be forwarded to the remote API when logged in. No access token will be sent when not logged in, and no OIDC flow is challenged to get an access token.
103113

104114
:::note
105115
These settings only specify the logic that is applied before the API call gets proxied. The remote APIs you are calling should always specify their own authorization and token requirements.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ builder.Services.AddBff()
6666
.AddBlazorServer();
6767

6868

69-
// ... <snip>..
69+
// ... <snip> ...
7070
7171
// Add the BFF middleware which performs anti forgery protection
7272
app.UseBff();
@@ -78,17 +78,15 @@ app.UseAntiforgery();
7878
// This has to be added after 'UseAuthorization()'
7979
app.MapBffManagementEndpoints();
8080

81-
// .. <snip>
81+
// ... <snip> ...
8282
```
8383

8484
```csharp
85-
8685
var builder = WebAssemblyHostBuilder.CreateDefault(args);
8786

8887
builder.Services
8988
.AddBffBlazorClient() // Provides auth state provider that polls the /bff/user endpoint
9089
.AddCascadingAuthenticationState();
9190

9291
builder.Services.AddLocalApiHttpClient<WeatherHttpClient>();
93-
9492
```

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ You set the options at startup time:
1919
```cs
2020
builder.Services.AddBff(options =>
2121
{
22-
// configure options here..
22+
// configure options here...
2323
})
2424
```
2525

@@ -154,7 +154,7 @@ In WASM, you configure the **BffBlazorClientOptions** using the **AddBffBlazorCl
154154
```csharp
155155
builder.Services.AddBffBlazorClient(opt =>
156156
{
157-
// configure options here..
157+
// configure options here...
158158
})
159159
```
160160

src/content/docs/bff/fundamentals/session/server-side-sessions.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ Just enable session cleanup:
6969
```csharp
7070
var cn = _configuration.GetConnectionString("db");
7171

72-
builder.Services.AddBff(options => {
72+
builder.Services.AddBff(options =>
73+
{
7374
options.EnableSessionCleanup = true;
7475
})
75-
.AddEntityFrameworkServerSideSessions(options=>
76+
.AddEntityFrameworkServerSideSessions(options =>
7677
{
7778
options.UseSqlServer(cn);
7879
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
label: "Getting Started"
2+
collapsed: true
3+
order: 1

0 commit comments

Comments
 (0)