Duende BFF Security Framework v3.0 to v4.0
Duende BFF Security Framework v4.0 is a significant release that includes:
- Multi-frontend support
- OpenTelemetry support
- Support for login prompts
- Several fixes and improvements
The extensibility approach has been drastically changed, and many virtual methods containing implementation logic are now internal instead.
Upgrading
Section titled “Upgrading”This release introduces many breaking changes. This upgrade guide covers cases where a breaking change was introduced.
Remote APIs
Section titled “Remote APIs”The syntax for configuring remote APIs has changed slightly:
// Use a client credentials token app.MapRemoteBffApiEndpoint("/api/client-token", "https://localhost:5010") .RequireAccessToken(TokenType.Client);
app.MapRemoteBffApiEndpoint("/api/client-token", new Uri("https://localhost:5010")) .WithAccessToken(RequiredTokenType.Client);
// Use the client token only if the user is logged in app.MapRemoteBffApiEndpoint("/api/optional-user-token", "https://localhost:5010") .WithOptionalUserAccessToken();
app.MapRemoteBffApiEndpoint("/api/optional-user-token", new Uri("https://localhost:5010")) .WithAccessToken(RequiredTokenType.UserOrNone);- The enum
TokenTypehas been renamed toRequiredTokenType, and moved from theDuende.BfftoDuende.Bff.AccessTokenManagementnamespace. - The methods to configure the token type have all been replaced with a new method
WithAccessToken() - Requesting an optional access token should no longer be done by calling
WithOptionalUserAccessToken(). UseWithAccessToken(RequiredTokenType.UserOrNone)instead.
Configuring Token Types In YARP
Section titled “Configuring Token Types In YARP”The required token type configuration in YARP has also changed slightly. It uses the enum values from RequiredTokenType.
Extending The BFF
Section titled “Extending The BFF”Simplified Wireup Without Explicit Authentication Setup
Section titled “Simplified Wireup Without Explicit Authentication Setup”The V3 style of wireup still works, but BFF V4 comes with a newer style of wireup:
services.AddBff() .ConfigureOpenIdConnect(options => { options.Authority = "your authority"; options.ClientId = "your client id"; options.ClientSecret = "secret"; // ... other OpenID Connect options. } .ConfigureCookies(options => { // The cookie options are automatically configured with recommended practices. // However, you can change the config here. });Adding this will automatically configure a Cookie and OpenID Connect flow.
Adding Multiple Frontends
Section titled “Adding Multiple Frontends”You can statically add a list of frontends by calling the AddFrontends method.
.AddFrontends( new BffFrontend(BffFrontendName.Parse("default-frontend")) .WithCdnIndexHtmlUrl(new Uri("https://localhost:5005/static/index.html")),
new BffFrontend(BffFrontendName.Parse("with-path")) .WithOpenIdConnectOptions(opt => { opt.ClientId = "bff.multi-frontend.with-path"; opt.ClientSecret = "secret"; }) .WithCdnIndexHtmlUrl(new Uri("https://localhost:5005/static/index.html")) .MapToPath("/with-path"),
new BffFrontend(BffFrontendName.Parse("with-domain")) .WithOpenIdConnectOptions(opt => { opt.ClientId = "bff.multi-frontend.with-domain"; opt.ClientSecret = "secret"; }) .WithCdnIndexHtmlUrl(new Uri("https://localhost:5005/static/index.html")) .MapToHost(HostHeaderValue.Parse("https://app1.localhost:5005")) .WithRemoteApis( new RemoteApi("/api/user-token", new Uri("https://localhost:5010")), new RemoteApi("/api/client-token", new Uri("https://localhost:5010")))Loading Configuration From IConfiguration
Section titled “Loading Configuration From IConfiguration”Loading configuration, including OpenID Connect configuration from IConfiguration is now supported:
services.AddBff().LoadConfiguration(bffConfig);This enables you to configure your OpenID Connect options, including secrets, and configure the list of frontends. This also adds a file watcher, to automatically add / remove frontends from the config file.
See the type BffConfiguration to see what settings can be configured.
Handling SPA Static Assets
Section titled “Handling SPA Static Assets”The BFF can be configured to handle the static file assets that are typically used when developing SPA based apps.
Proxying Only index.html
Section titled “Proxying Only index.html”When deploying a multi-frontend BFF, it makes most sense to have the frontends configured with an index.html file that is retrieved from a Content Delivery Network (CDN).
This can be done in various ways. For example, if you use Vite, you can publish static assets with a base URL configured. This will make sure that any static asset, (such as images, scripts, etc.) are retrieved directly from the CDN for best performance.
var frontend = new BffFrontend(BffFrontendName.Parse("frontend1")) .WithCdnIndexHtml(new Uri("https://my_cdn/some_app/index.html"))The BFF automatically wires up a catch-all route that servesindex.html for that specific frontend.
See Serve the index page from the BFF host for more information.
Proxying All Static Assets
Section titled “Proxying All Static Assets”When developing a Single-Page Application (SPA), it’s very common to use a development webserver such as Vite. While Vite can publish static assets with a base URL, this doesn’t work well during development.
The best development experience can be achieved by configuring the BFF to proxy all static assets from the development server:
var frontend = new BffFrontend(BffFrontendName.Parse("frontend1")) .WithProxiedStaticAssets(new Uri("https://localhost:3000")); // https://localhost:3000 would be the URL of your development web server.While this can also be done in production, it will proxy all static assets through the BFF. This will increase the bandwidth consumed by the BFF and reduce the overall performance of your application.
Proxying Assets Based On Environment
Section titled “Proxying Assets Based On Environment”If you’re using a local development server during development and a CDN in production, you can configure this as follows:
// In this example, the environment name from the application builder is used to determine// if we're running in production or not.var runningInProduction = () => builder.Environment.EnvironmentName == Environments.Production;
// Then, when configuring the frontend, you can switch when the static assets will be proxied.new BffFrontend(BffFrontendName.Parse("default-frontend")) .WithBffStaticAssets(new Uri("https://localhost:5010/static"), useCdnWhen: runningInProduction);Server Side Sessions Database Migrations
Section titled “Server Side Sessions Database Migrations”When using the server side sessions feature backed by the Duende.BFF.EntityFramework package, you will need to script Entity Framework database migrations and apply these changes to your database.
dotnet ef migrations add BFFUserSessionsV4 -o Migrations -c SessionDbContextIn the UserSessions table, a number of changes were introduced:
- The
ApplicationNamecolumn was renamed toPartitionKey. This column will contain the BFF frontend name. - Related indexes were updated.
ALTER TABLE "UserSessions" RENAME COLUMN "ApplicationName" TO "PartitionKey";
DROP INDEX "IX_UserSessions_ApplicationName_SubjectId_SessionId";CREATE UNIQUE INDEX "IX_UserSessions_PartitionKey_SubjectId_SessionId" ON "UserSessions" ("PartitionKey", "SubjectId", "SessionId");
DROP INDEX "IX_UserSessions_ApplicationName_SessionId";CREATE UNIQUE INDEX "IX_UserSessions_PartitionKey_SessionId" ON "UserSessions" ("PartitionKey", "SessionId");
DROP INDEX "IX_UserSessions_ApplicationName_Key";CREATE UNIQUE INDEX "IX_UserSessions_PartitionKey_Key" ON "UserSessions" ("PartitionKey", "Key");