---
title: "BFF in ASP.NET Core #7 - Introducing the Duende BFF Library"
description: "How to replace a custom BFF in ASP.NET Core with the Duende BFF library: setup, management endpoints, local and remote APIs and sign-out. Part 7 of the series."
url: https://nestenius.se/net/bff-in-asp-net-core-7-introducing-the-duende-bff-library/
date: 2025-08-20
author: "Tore Nestenius"
category: ".NET"
tags: ["bff", "identityserver"]
site: https://nestenius.se/
---

# BFF in ASP.NET Core #7 - Introducing the Duende BFF Library

In the previous blog posts in this series, we built our own Backend-for-Frontend (BFF) implementation in ASP.NET Core from scratch. Now, you might be wondering about how much effort it would take to replace our custom solution with the [Duende BFF Security Framework](https://docs.duendesoftware.com/bff/)? In this post, we'll walk through that migration process and see just how straightforward it can be.

This is a big topic, so I’ve split it into multiple parts. You can jump to the section you need, but for background and context, it's best to start here:

[Part 1 - Introduction](https://nestenius.se/net/implementing-bff-pattern-in-asp-net-core-for-spas/)  
[Part 2 - Introducing the Backend-for-Frontend (BFF) pattern](https://nestenius.se/net/bff-in-asp-net-core-2-the-bff-pattern-explained/)  
[Part 3 - Securing the Cookie Session](https://nestenius.se/net/bff-in-asp-net-core-3-the-bff-pattern-explained/)  
[Part 4 - Implementing a BFF in ASP.NET Core](https://nestenius.se/net/bff-in-asp-net-core-4-implementing-a-bff-from-scratch/)  
[Part 5 - Automatic Token Renewal](https://nestenius.se/net/bff-in-asp-net-core-5-automatic-token-renewal/)  
[Part 6 - Securing the BFF using CORS](https://nestenius.se/net/bff-in-asp-net-core-6-securing-our-bff-with-cors/)  
**Part 7 - Introducing the Duende BFF Library**

Series overview: [BFF in ASP.NET Core, the guide to all seven parts](https://nestenius.se/bff/)

## Introducing the Duende BFF Library

The [Duende BFF (Backend For Frontend) Security Framework](https://duendesoftware.com/products/capabilities/backend-for-frontend) is a comprehensive ASP.NET Core library that’s designed to secure browser-based applications like SPAs and Blazor apps by implementing the modern Backend-For-Frontend security pattern.

This library provides a robust set of features that address the common security challenges of modern web applications:

This library provides features like:

- Token extraction attack protection - keeps access tokens server-side
- Built-in CSRF attack protection through custom header requirements
- Server-side OAuth 2.0 support with complete protocol handling
- Multi-frontend support
- API reverse proxy capabilities for secure external API access
- Server-side session state management
- Back-channel logout support
- Blazor authentication state management
- And more…

## Duende BFF Licensing

Before implementing [Duende BFF](https://duendesoftware.com/products/capabilities/backend-for-frontend) in your project, it's important to understand the licensing model. While the library is free for development, testing, and personal projects, production usage may require a commercial license depending on your business size and requirements. Duende Software also offers [community editions](https://duendesoftware.com/products/communityedition) and startup-friendly options.  

For the most current licensing information and to determine what applies to your specific situation, visit the Duende Software website directly.

## The Duende BFF Source Code

You can find all the code for this tutorial series on [GitHub](https://github.com/tndataab/PublicBlogContent/tree/main/Backend-For-Frontend), with the specific implementation for this post located in the **5-Duende.BFF** project folder. Having the complete working example will help you to follow along and see the migration in action.  

**Important**: You'll need to provide your own OIDC authentication server details to run the sample code successfully.

## Adding the Duende.BFF NuGet Package

The first step in is to add the following NuGet packages:

![Duende Backend For Frontend (BFF) Security Framework NuGet package](https://nestenius.se/_astro/duende-bff-nuget-package-listing.4GPBLQo4_13uIpP.webp) ![Duende.BFF.Yarp NuGet package](https://nestenius.se/_astro/duende-bff-yarp-nuget-package-verified.BwRW7Ixg_ColhH.webp)

The [**Duende.BFF.Yarp**](https://www.nuget.org/packages/Duende.BFF.Yarp) package is needed in order to support remote APIs.

## Removing Duende.AccessTokenManagement.OpenIdConnect

Our previous implementation used the [**Duende.AccessTokenManagement.OpenIdConnect**](https://www.nuget.org/packages/Duende.AccessTokenManagement.OpenIdConnect) package for automatic token management. However, since Duende.BFF already includes this dependency; we need to remove the standalone package from our project to prevent library version conflicts.

**Important:** Failing to remove this package may cause your application to fail during startup due to conflicting dependencies.

## Configuring Duende.BFF

Now we need to register the Duende BFF services in our Program class:

```csharp
// Add Duende BFF services builder.Services.AddBff()
.AddRemoteApis();
```

The **AddBff()** method registers the core BFF framework services (authentication, session management, local API protection), while **AddRemoteApis()** adds the additional services needed specifically for proxying requests to external APIs using YARP (Yet Another Reverse Proxy).

Next, we add the BFF middleware to our request pipeline. Note the specific order of these middleware components. **UseBff()** must be placed before **UseAuthorization()** because anti-forgery validation needs to happen before authorization decisions are made:

```csharp
app.UseAuthentication();
app.UseBff();
app.UseAuthorization();
```

The **app.UseBff()** middleware automatically handles X-CSRF header validation. The middleware examines endpoint metadata to identify BFF-protected endpoints and validates that requests include the required X-CSRF header.  

Since this protection is now handled by the framework, we can now remove our custom CSRF component:

```csharp
// Remove this code 
app.CheckForCsrfHeader();
```

## The BFF Management Endpoints

In our custom BFF implementation, we created a **BffController** class that handled login, logout, and session information retrieval. With Duende BFF, we can remove this entire controller since the framework provides these endpoints automatically.

To enable the BFF management endpoints, add this single line to your request pipeline:

```csharp
// Map BFF endpoints 
app.MapBffManagementEndpoints();
```

This automatically exposes the following endpoints:

- **/bff/login**  
    Initiates the login process.
- **/bff/silent-login**
- **/bff/silent-login-callback**  
    Support silent login flows.
- **/bff/logout**  
    Initiates the logout process.
- **/bff/user**  
    Returns information about the currently logged-in user.
- **/bff/backchannel**  
    Handles OpenID Connect back-channel logout notifications.
- **/bff/diagnostics**  
    Exposes diagnostics information (enabled only in development environments by default)

## Mapping of Local APIs

Our existing local API in the **ApiController** can remain largely unchanged. We simply need to add the **\[BffApi\]** attribute to the controller class:

```csharp
[ApiController] 
[Route("api")] 
[Authorize] 
[BffApi] 
public class ApiController : ControllerBase 
{
    ...
}
```

The **\[BffApi\]** attribute automatically applies the security measures recommended for browser-based applications following the BFF pattern. This includes CSRF protection and proper token handling.

## Mapping of Remote APIs

In our custom implementation, we handled remote API proxying through a method in the ApiController. This approach required manually proxying requests to **/bff/remote** while replacing the session cookie with the appropriate access token.

As you experienced firsthand, implementing this correctly involved quite a bit of complex code. Duende BFF simplifies this dramatically by leveraging Microsoft's **YARP** (Yet Another Reverse Proxy) library to do this work for us.

This means we can replace our entire custom action method with this single line of code (in **Program.cs**):

```csharp
app.MapRemoteBffApiEndpoint("/api/remote",
            new Uri("https://www.secure.nu/tokenapi/gettime"))
			.WithAccessToken(RequiredTokenType.User);
```

his approach significantly reduces the complexity and code required to implement secure remote API access, while also providing a high-performance proxy solution that would be difficult to implement ourselves.

## Tweaking the frontend

We'll make some small adjustments to the frontend by adding new buttons to the homepage that demonstrate the various BFF endpoints:

![Tweaking the frontend We'll make some small adjustments to the frontend by adding new buttons to the homepage that demonstrate the various BFF endpoints:](https://nestenius.se/_astro/bff-spa-authentication-api-actions-buttons.ItwF1TdI_1vJCEx.webp)

Each button serves a specific testing purpose:

- **Get User**  
    Calls the **/bff/user** endpoint to retrieve data about the currently logged-in user and session information.
- **Diagnostics**  
    Calls the **/bff/diagnostics** endpoint, which returns current user details and client access token for testing purposes.
- **Get Identity**  
    Calls a custom **/user/GetIdentity** endpoint that we've implemented in a custom UserController class. This endpoint returns the raw ClaimsPrincipal authentication properties, cookie details, and session cookie information as seen by ASP.NET Core controllers. Since ASP.NET Core sometimes abstracts or transforms authentication data, this endpoint helps verify your assumptions during development.

## Signing Out

To implement proper logout functionality, we need to make some minor adjustments to our application. Simply calling the **/bff/logout** endpoint isn't sufficient. We must include the internal session ID as a query string parameter for security purposes.

This **session ID** requirement acts as CSRF protection for the logout endpoint, preventing attackers from maliciously signing users out of their sessions.

```text
The logout URL with the session ID looks like this:
/bff/logout?sid=xxxxxxxxxSessionIDxxxxxxxxxxxx
```

The easiest way to obtain this complete logout URL is through the **/bff/user** endpoint, which includes a claim named **bff:logout\_url** that contains the properly formatted logout URL.

You can find all the implementation details for this logout flow in the **site.js** JavaScript file.

## Testing our implementation

With all these changes in place, we can verify that our application works exactly as before. Users can sign in to the BFF application and receive an authentication session cookie, maintaining the same user experience while benefiting from the enhanced security and simplified codebase.

## The Journey from DIY to Production-Ready

Migrating from our custom BFF implementation to **Duende BFF** proved to be remarkably straightforward. The transition required only a few minor adjustments to achieve the same functionality we had before, but with significant improvements under the hood.

The **YARP** **integration** particularly stands out, providing a much more robust and modern approach to remote API proxying compared to our prototype implementation. This upgrade gives us enterprise-grade reliability with minimal effort.

While there are many additional configuration options and advanced features we could explore, those topics will have to wait for future blog posts or webinars. The foundation we've built here provides a solid starting point for most applications.

## Summary

Throughout this blog series, we've built a comprehensive BFF implementation in ASP.NET Core and secured it using industry best practices. Our goal has been to provide you with a deep understanding of how a BFF works under the hood, whether you plan to build your own solution or leverage an existing one.

Existing BFF Solutions:

- **[Duende.BFF](https://duendesoftware.com/products/capabilities/backend-for-frontend)**  
    Enterprise-grade solution from the creators of Duende IdentityServer
- [**OidcProxy.Net**](https://github.com/oidcproxydotnet/OidcProxy.Net)  
    A developer-friendly, open-source identity-aware reverse proxy built on YARP that requires minimal configuration to implement the BFF pattern for SPAs.

We've demonstrated that the BFF pattern is one of the most effective ways to harden SPA applications. It allows us to:

- Leverage the browser's built-in security features to their fullest potential
- Keep sensitive authentication tokens and session data away from the frontend
- Implement robust CORS protection against cross-origin attacks
- Maintain a secure authentication flow without exposing credentials to JavaScript

**The key insight:** Understanding how a BFF works under the hood is essential for using it securely and effectively, regardless of whether you build your own or adopt an existing solution.

With the foundation we've built in this series, you're now equipped to make informed decisions about BFF implementation and configuration in your own applications.

I hope you've found this blog post series valuable! Please [share](https://nestenius.se/contact/) your thoughts and experiences as you implement these patterns in your own projects.

## What Did We Not Cover?

What we've built so far is a solid starting point for a custom BFF setup. However, there are several important production considerations you may want to explore further:

- **Reducing Authentication Cookie Size**  
    To keep your authentication cookies small and secure, consider using a cookie session store. Large cookies can impact performance and hit browser size limits. See this blog post for more details: [Improving ASP.NET Core Security By Putting Your Cookies On A Diet](https://nestenius.se/net/improving-asp-net-core-security-by-putting-your-cookies-on-a-diet/).
- **Logging and Monitoring**  
    Proper logging is essential for troubleshooting and security auditing, but was not included in this walkthrough. Consider implementing structured logging for authentication events, failed requests, and security-related activities.
- **Data Protection Configuration**  
    ASP.NET Core uses the Data Protection API for critical functions like cookie encryption. In production environments, you'll want to configure this properly! I’ve covered it in the following posts: [Persisting the ASP.NET Core Data Protection Key Ring in Azure Key Vault](https://nestenius.se/net/persisting-the-asp-net-core-data-protection-key-ring-in-azure-key-vault/)  
    and [Introducing the Data Protection API Key Ring Debugger](https://nestenius.se/net/introducing-the-data-protection-api-key-ring-debugger/).
- **Forwarded Headers Middleware**  
    If your application runs behind a reverse proxy or terminates HTTPS at a load balancer or gateway, you'll need to configure forwarded headers correctly to maintain security. For more details, see my blog post:  
    [Configuring ASP.NET Core Forwarded Headers Middleware](https://nestenius.se/net/configuring-asp-net-core-forwarded-headers-middleware/).
- **Using YARP as a Reverse Proxy**  
    In our examples, we hand-coded the proxy logic between the browser and remote APIs. For a more flexible and high-performance solution, consider using YARP (Yet Another Reverse Proxy). [YARP Documentation](https://dotnet.github.io/yarp/)
- **Content Security Policy (CSP)**  
    With the BFF pattern, you can implement a strict Content Security Policy since the frontend is served from your backend. This provides powerful protection against XSS attacks and reduces the risk of compromised browsers executing malicious scripts.
- **Shared Storage for Scaling**  
    When scaling your BFF across multiple instances, you'll need shared storage (like Redis or SQL Server) for access tokens and session data to prevent race conditions, especially with Identity Providers that don't allow refresh token reuse.
- **Authorization Policies**  
    Authorization Policies Beyond authentication (which the BFF manages for us), you'll need to implement proper authorization using ASP.NET Core's policy-based authorization system to control what authenticated users can access.

## Resources

- [YARP](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/yarp/yarp-overview?) (Yet Another Reverse Proxy)
- [BFF Session Management Endpoints](https://docs.duendesoftware.com/bff/fundamentals/session/management/)
- [Implement BFF with ASP.NET Core and IdentityServer](https://duendesoftware.com/learn/implementing-secure-bff-with-asp-dot-net-core-and-duende-identityserver)
- [Duende BFF Logout Endpoint](https://docs.duendesoftware.com/bff/fundamentals/session/management/logout/)
- [Set up a SPA+BFF with ASP.NET Core and Angular in 3 steps (.NET 8)](https://abstarreveld.medium.com/set-up-a-spa-bff-with-asp-net-core-and-angular-in-3-steps-net-8-18527d73bc43)

## Related posts

- [Duende IdentityServer 7: A Complete Setup Guide for ASP.NET Core](https://nestenius.se/net/duende-identityserver-7-a-complete-setup-guide-for-asp-net-core/)
- [IdentityServer - IdentityResource vs. ApiResource vs. ApiScope](https://nestenius.se/net/identityserver-identityresource-vs-apiresource-vs-apiscope/)
- [Pushed Authorization Requests (PAR) in ASP.NET Core 9](https://nestenius.se/net/pushed-authorization-requests-par-in-asp-net-core-9/)
- [Improving ASP.NET Core Security By Putting Your Cookies On A Diet](https://nestenius.se/net/improving-asp-net-core-security-by-putting-your-cookies-on-a-diet/)

## Related Training Workshops

Ready to take your web security skills to the next level? If you want to deepen your understanding of web application security, OpenID Connect, or authentication in .NET, explore the [comprehensive workshops available](https://tn-data.se/training/).

These hands-on, practical workshops are specifically designed for developers working with real-world applications and modern identity solutions. You'll gain actionable knowledge that you can immediately apply to secure your own projects.

## Feedback, comments, found any bugs?

Have feedback, spotted an issue, or found a typo? I'd love to hear from you! Your input helps improve the content and assists other developers who might encounter similar challenges. [Get in touch!](https://nestenius.se/contact/)
