Pisum.BFF 1.11.0

Pisum.Bff

NuGet License

Core library for the Pisum Backend for Frontend (BFF) security pattern implementation.

Overview

Pisum.Bff is a comprehensive security framework that implements the Backend for Frontend (BFF) pattern for ASP.NET Core applications. It moves authentication to the server-side, implements secure session management, and provides CSRF protection for modern SPAs (Single Page Applications).

Key Features

  • Server-Side Authentication - No tokens in browser, httpOnly secure cookies
  • Secure Session Management - Server-side session storage with distributed cache support
  • CSRF Protection - Anti-forgery tokens for all state-changing requests
  • OpenID Connect - Works with any OIDC-compliant identity provider
  • Flexible Endpoints - Login, logout, user info, and backchannel logout
  • Session Revocation - Logout from all sessions or specific sessions
  • Background Cleanup - Automatic cleanup of expired sessions

Installation

From Pisum NuGet Server

dotnet add package Pisum.BFF --source https://nuget.pisum.synology.me/v3/index.json

Or via Package Manager:

Install-Package Pisum.BFF -Source https://nuget.pisum.synology.me/v3/index.json

Configure NuGet Source

Add the Pisum NuGet server to your NuGet configuration:

dotnet nuget add source https://nuget.pisum.synology.me/v3/index.json --name Pisum

Then install normally:

dotnet add package Pisum.BFF

Quick Start

1. Configure Services

// Program.cs or Startup.cs
using Pisum.Bff.Endpoints;

var builder = WebApplication.CreateBuilder(args);

// Add BFF services
builder.Services.AddBffCore(options =>
{
    options.AnonymousSessionResponse = AnonymousSessionResponse.Response401;
    options.AntiforgeryHeaderName = "X-CSRF-TOKEN";
    options.AntiforgeryHeaderValue = "1";
    options.EnableAntiForgery = true;
    options.ManagementBasePath = "/bff";
})
.AddServerSideSessions();

// Add authentication
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "cookie";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("cookie", options =>
{
    options.Cookie.Name = "__Host-bff";
    options.Cookie.SameSite = SameSiteMode.Strict;
})
.AddOpenIdConnect("oidc", options =>
{
    options.Authority = "https://your-identity-provider";
    options.ClientId = "your-client-id";
    options.ClientSecret = "your-client-secret";
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.SaveTokens = true;
});

var app = builder.Build();

2. Configure Middleware Pipeline

// IMPORTANT: Middleware order matters!
app.UseSession();              // 1. Enable session support
app.UseAuthentication();       // 2. Authentication middleware
app.UseBffMiddleware();        // 3. BFF-specific validation
app.UseAuthorization();        // 4. Authorization middleware
app.UseAntiforgery();          // 5. Anti-forgery token validation

// Map BFF management endpoints
app.MapBffManagementEndpoints();

app.Run();

3. Client-Side Usage

// Login
window.location.href = '/bff/login?returnUrl=/';

// Get user information
const response = await fetch('/bff/user', {
    headers: { 'X-CSRF-TOKEN': '1' }
});
const user = await response.json();

// Logout
await fetch('/bff/logout', {
    method: 'POST',
    headers: { 'X-CSRF-TOKEN': '1' }
});

Architecture

Security Model

┌─────────────────┐          ┌─────────────────┐
│   SPA Client    │          │   BFF Server    │
│  (Browser)      │          │  (ASP.NET Core) │
└────────┬────────┘          └────────┬────────┘
         │                            │
         │  1. Login Request          │
         ├───────────────────────────>│
         │                            │
         │  2. Redirect to IdP        │
         │<───────────────────────────┤
         │                            │
         │  3. Authenticate at IdP    │
         │                            │
         │  4. Return to BFF          │
         ├───────────────────────────>│
         │                            │
         │  5. Store session          │
         │     (server-side)          │
         │                            │
         │  6. Set httpOnly cookie    │
         │<───────────────────────────┤
         │                            │
         │  7. API calls with cookie  │
         ├───────────────────────────>│
         │     + CSRF token            │
         │                            │

Key Security Benefits:

  • ❌ No access tokens in browser
  • ✅ Tokens stored server-side only
  • ✅ httpOnly, secure cookies
  • ✅ CSRF protection
  • ✅ Session validation on every request

Core Components

Configuration

BffOptions

public class BffOptions
{
    // Anonymous session handling
    public AnonymousSessionResponse AnonymousSessionResponse { get; set; }

    // Anti-forgery configuration
    public bool EnableAntiForgery { get; set; } = true;
    public string AntiforgeryHeaderName { get; set; } = "X-CSRF-TOKEN";
    public string AntiforgeryHeaderValue { get; set; } = "1";

    // Endpoint configuration
    public string ManagementBasePath { get; set; } = "/bff";
    public string LoginEndpoint { get; set; } = "/login";
    public string LogoutEndpoint { get; set; } = "/logout";
    public string UserEndpoint { get; set; } = "/user";

    // Session configuration
    public TimeSpan SessionLifetime { get; set; } = TimeSpan.FromHours(8);
    public TimeSpan SlidingExpiration { get; set; } = TimeSpan.FromHours(1);
}

Session Management

Server-Side Sessions

// In-memory session store (development)
builder.Services.AddBffCore()
    .AddServerSideSessions();

// Distributed cache session store (production)
builder.Services.AddBffCore()
    .AddServerSideSessions(options =>
    {
        options.CacheName = "bff-sessions";
    });

// Configure distributed cache (Redis example)
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost:6379";
});

Session Revocation

public class MyService
{
    private readonly ISessionRevocationService _revocation;

    public MyService(ISessionRevocationService revocation)
    {
        _revocation = revocation;
    }

    public async Task RevokeUserSessionsAsync(string userId)
    {
        await _revocation.RevokeSessionAsync(userId);
    }
}

Endpoints

The BFF provides the following management endpoints:

Endpoint Method Description
/bff/login GET Initiates login flow
/bff/logout POST Logs out current session
/bff/user GET Returns current user claims
/bff/backchannel-logout POST Handles backchannel logout from IdP

Customizing Endpoints

// Custom login service
public class CustomLoginService : ILoginService
{
    public Task ProcessRequestAsync(HttpContext context)
    {
        // Custom login logic
    }
}

builder.Services.AddSingleton<ILoginService, CustomLoginService>();

Middleware

BffMiddleware performs:

  1. Session validation
  2. Anti-forgery token validation
  3. Request authentication checks
  4. Endpoint-specific security
// Mark endpoints as BFF API endpoints
[BffApi]
[HttpGet("/api/data")]
public IActionResult GetData()
{
    return Ok(new { data = "secure data" });
}

// Mark endpoints as BFF UI endpoints
[BffUIEndpoint]
[HttpGet("/secure-page")]
public IActionResult SecurePage()
{
    return View();
}

Advanced Configuration

CSRF Token Customization

builder.Services.AddBffCore(options =>
{
    // For Angular (uses custom header)
    options.AntiforgeryHeaderName = "X-CSRF";
    options.AntiforgeryHeaderValue = "1";

    // For React/Vue (default)
    options.AntiforgeryHeaderName = "X-CSRF-TOKEN";
    options.AntiforgeryHeaderValue = "1";
});

Anonymous Session Handling

builder.Services.AddBffCore(options =>
{
    // Return 401 for anonymous users (default)
    options.AnonymousSessionResponse = AnonymousSessionResponse.Response401;

    // Return 200 with anonymous claims
    options.AnonymousSessionResponse = AnonymousSessionResponse.Response200;
});

Background Cleanup

// Automatic cleanup runs every 1 hour by default
builder.Services.AddBffCore()
    .AddServerSideSessions(options =>
    {
        options.CleanupInterval = TimeSpan.FromMinutes(30);
    });

Target Frameworks

  • .NET 8.0
  • .NET 9.0

Dependencies

  • Duende.AccessTokenManagement.OpenIdConnect (3.2.0) - Token management
  • Duende.IdentityModel (7.1.0) - Identity model utilities
  • Pisum.Bff.Shared (1.0.0) - Shared models

Examples

See the samples directory for complete examples:

  • Demo.Bff.Blazor.Server - Blazor Server with BFF pattern
  • Demo.Bff.Angular - Angular SPA with BFF pattern

Best Practices

  1. Always use HTTPS in production
  2. Enable anti-forgery tokens for all state-changing requests
  3. Use distributed cache for session storage in production
  4. Set appropriate session lifetime based on your security requirements
  5. Implement session cleanup to remove expired sessions
  6. Monitor session store for performance and capacity
  7. Use secure cookie settings (httpOnly, secure, sameSite)

Security Considerations

  • Access tokens are never exposed to the browser
  • All sessions are stored server-side
  • CSRF protection is enabled by default
  • Sessions can be revoked centrally
  • Supports backchannel logout from identity provider

Contributing

This is part of the Pisum BFF framework. For contributions and issues, please refer to the main repository.

License

Copyright © 2025 pisum.net

Support

For questions and support, please open an issue in the main repository.

Showing the top 20 packages that depend on Pisum.BFF.

Packages Downloads
Pisum.Bff.Yarp
Pisum Backend for Frontend (BFF) security framework YARP library.
62

Version Downloads Last updated
1.11.0 62 10/21/2025
1.10.0 34 10/09/2025
1.9.0 13 10/09/2025
1.8.1-preview 3 10/09/2025