Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 35 additions & 12 deletions src/content/docs/bff/architecture/multi-frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,59 @@ sidebar:
variant: tip
---

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.
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.

A single BFF setup consists of:
1. A browser based application, typically built using technology like React, Angular or VueJS. This is typically deployed to a Content Delivery Network (CDN).
2. A BFF host, that will take care of the OpenID Connect login flows.
3. An API surface, exposed and protected by the BFF.

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.
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 Hosts or Paths to distinguish), it's possible to
create very flexible setups.

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).
The BFF dynamically configures the aspnet core authentication pipeline according to recommended practices. For example,
when doing Host 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).

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.
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.

:::note
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.
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.
:::

## A Typical Example

Consider an enterprise that hosts multiple browser based applications. Each of these applications is developed by a separate team and as such, has its own deployment schedule.
Consider an enterprise that hosts multiple browser based applications. Each of these applications is developed by a
separate team and as such, has its own deployment schedule.

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`.
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`.

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`
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`

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.md) feature of Duende IdentityServer.
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.md) feature of
Duende IdentityServer.

This setup, with multiple frontends, each having different authentication requirements and different API surfaces, is now supported by the BFF.
This setup, with multiple frontends, each having different authentication requirements and different API surfaces,
is now supported by the BFF.

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.
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.

It's also possible to dynamically add or remove frontends, without restarting the BFF host.

Expand All @@ -51,7 +74,7 @@ To achieve this, the BFF automatically configures the ASP.NET Core pipeline:

![BFF Multi-Frontend Pipeline](../images/bff_multi_frontend_pipeline.svg)

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.
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 and host based routing, so the most specific will be selected.
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.
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.
4. Your own applications logic is executed in this part of the pipeline. For example, calling `.UseAuthentication(), .UseRequestLogging()`, etc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The configuration supports dynamic reloading (so any new frontend added / remove
Example: `"/from-config"`

- `matchingHostHeader`
The origin to match for this frontend.
The host to match for this frontend.
Example: `"https://localhost:5005"`

- `oidc`
Expand Down
15 changes: 10 additions & 5 deletions src/content/docs/bff/fundamentals/multi-frontend/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ To overcome this issue, a single BFF instance can support multiple frontends. Ea
* Define its own OpenID Connect configuration
* Define its own Cookie settings
* Define its own API surface
* Be identified either via path based routing and/or origin selection.
* Be identified either via path based routing and/or host selection.

Adding additional frontends to the BFF has very little impact on the performance on the BFF itself, but keep in mind
that the traffic for all the frontends is proxied through the BFF.
Expand Down Expand Up @@ -94,13 +94,18 @@ as via [Configuration](configuration.mdx).

## Frontend Selection

Each request to a frontend has to be uniquely defined by either its path, its origin or a combination of the two.
If you specify neither, then it's considered the default frontend.
Each request to a frontend has to be uniquely defined by either its path, its host or a combination of the two.
If you specify neither, then it's considered the default frontend.

:::note
With "host", we mean the combination of the schema (http/https), the domain (app1.example.com) and the port. The BFF
frontend selection middleware uses the HTTP Host header to select a matching frontend.
:::

Frontends are matched using the following algorithm:

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, it's selected.
2. **Selection by origin only:** Then, if there is a frontend with only origins configured and it matches the path, it's selected.
1. **Selection by both host and path:** If there is a frontend that matches both the host AND has the most specific match to a path, it's selected.
2. **Selection by host only:** Then, if there is a frontend with only hosts configured and it matches the path, it's selected.
3. **Selection by path only:** Then, if there is a frontend with a matching path specified, it's selected.
4. **Default frontend:** Then, if there is a default frontend configured, it's selected.

Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/bff/getting-started/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar:
label: Overview
---

Currently, the most recent version is 4 (preview 2). If you're upgrading from a previous version, please check our [upgrade guides](/bff/upgrading).
Currently, the most recent version is v4. If you're upgrading from a previous version, please check our [upgrade guides](/bff/upgrading).

If you're starting a new BFF project, consider the following startup guides:

Expand Down
10 changes: 7 additions & 3 deletions src/content/docs/bff/getting-started/multi-frontend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ sidebar:
import { Code } from "@astrojs/starlight/components";
import { Tabs, TabItem } from "@astrojs/starlight/components";

Duende.BFF (Backend for Frontend) supports multiple frontends in a single BFF host. This is useful for scenarios where you want to serve several SPAs or frontend apps from the same backend, each with their own authentication and API proxying configuration.
Duende.BFF (Backend for Frontend) supports multiple frontends in a single BFF host. This is useful for scenarios where
you want to serve several SPAs or frontend apps from the same backend, each with their own authentication and API
proxying configuration.

:::note
Multi-frontend support is available in Duende.BFF v4 and later. The v3-style of wiring up BFF is not supported for this scenario.
Multi-frontend support is available in Duende.BFF v4 and later. The v3-style of wiring up BFF is not supported for
this scenario.
:::

## Prerequisites
Expand All @@ -39,7 +42,8 @@ dotnet add package Duende.BFF

### 3. OpenID Connect Configuration

Configure OpenID Connect authentication for your BFF host. This is similar to the single frontend setup, but applies to all frontends unless overridden per frontend.
Configure OpenID Connect authentication for your BFF host. This is similar to the single frontend setup, but applies
to all frontends unless overridden per frontend.

```csharp
// Program.cs
Expand Down