Skip to content
Version v3.2.0

Backend-For-Frontend (BFF) ​

Introduction ​

The configured ProAuthBff:AuthenticationSettings:Authority must exactly match the provider's discovery issuer, including any trailing slash. The BFF rejects a mismatch before using discovered endpoints or signing keys. Update an authority alias to the provider's published issuer when migrating an existing configuration.

The Backend-For-Frontend (BFF) pattern is a security architecture that places an intermediary server between your Single Page Application (SPA) and your backend APIs. This pattern addresses fundamental security limitations of browser-based applications when handling OAuth 2.0 / OpenID Connect tokens.

Application-owned loading and error pages ​

ProAuth.Bff provides authentication endpoints and session handling; it does not ship a loading screen, branded error page, or product logo. Each consuming application owns its startup UI and styling. Authentication failure handling can redirect to /Error, so the host should provide an anonymous recovery page at that path. Keep that page independent of the SPA and protected APIs so it can render when initialization fails, and avoid displaying raw exception details.

The ProAuth AdminApp implements its startup screens in React and its standalone /Error page in Razor, with a shared application-owned stylesheet. This branding is not included in the redistributable BFF package.

Why Use a BFF? ​

Traditional SPAs store access tokens in browser storage (localStorage or sessionStorage), which exposes them to several attack vectors:

RiskDescription
XSS AttacksMalicious scripts can steal tokens from browser storage
Token ExposureTokens visible in browser developer tools and network requests
Limited Token LifetimeShort-lived tokens require frequent refresh flows in the browser
Refresh Token SecurityStoring refresh tokens in the browser is inherently insecure

The BFF pattern solves these problems by:

  • Keeping tokens server-side: Access and refresh tokens never reach the browser
  • Using HTTP-only cookies: Session authentication via secure, HTTP-only cookies that JavaScript cannot access
  • Server-side token injection: The BFF injects bearer tokens into API requests on behalf of the user
  • Centralized token refresh: Automatic token refresh happens transparently on the server

Architecture ​

Getting Started ​

Prerequisites ​

  • .NET 9.0 or later
  • ASP.NET Core application
  • A ProAuth tenant with a configured client application

Package Installation ​

Add the BFF package and your chosen token store provider:

bash
# Core BFF package
dotnet add package ProAuth.Bff

# Choose ONE token store provider:
dotnet add package ProAuth.Oidc.Client.InMemory  # Development/Testing
dotnet add package ProAuth.Oidc.Client.Redis     # Production (distributed)
dotnet add package ProAuth.Oidc.Client.Dapr      # Dapr-based deployments
dotnet add package ProAuth.Oidc.Client.ReaFx    # ReaFx framework integration

Client authentication ​

With ClientAuthenticationMethod: Auto, a configured client secret selects ClientSecretBasic. The BFF sends those credentials in the HTTP Authorization header when redeeming an authorization code at the discovered token endpoint. This also works with DPoP enabled. Configure the same authentication method on the registered client application.

Basic Setup ​

Create a new ASP.NET Core application and configure the BFF in Program.cs:

csharp
using ProAuth.Bff.Extensions;
using ProAuth.Oidc.Client.InMemory;

var builder = WebApplication.CreateBuilder(args);

// Add health checks
builder.Services.AddHealthChecks();

// Add distributed cache for session support
builder.Services.AddDistributedMemoryCache();

// Add ProAuth BFF services
builder.Services.AddBff(builder.Configuration)
    .WithInProcessLocking()
    .WithInMemoryTokenStore()
    .WithInMemoryTicketStore();

var app = builder.Build();

// Configure middleware pipeline
app.UseForwardedHeaders();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();

app.MapControllers();
app.MapHealthChecks("/health");

// Map BFF reverse proxy routes
app.MapReverseProxy();

// SPA fallback
app.MapFallbackToFile("index.html");

app.Run();

Configuration ​

The BFF is configured through the ProAuthBff section in your application settings.

Configuration Structure ​

json
{
  "ProAuthBff": {
    "SessionTimeoutInMinutes": 60,
    "PasswordChangeUrlClaimType": "pwchangeurl",
    "ForwardedHeaders": {
      "UseForwardedHeaders": true,
      "ForwardLimit": 1,
      "KnownProxies": "",
      "KnownNetworks": ""
    },
    "Routes": [],
    "AuthenticationSettings": {
      "Authority": "https://auth.example.com",
      "ClientId": "my-spa-client",
      "ClientSecret": "client-secret",
      "ClientAuthenticationMethod": "Auto",
      "ClientAssertion": {
        "SigningAlgorithm": "RS256",
        "Certificate": "<base64-pfx>",
        "CertificatePath": null,
        "CertificatePassword": "<pfx-password>",
        "KeyId": "my-client-key",
        "LifetimeInSeconds": 60
      },
      "MutualTls": {
        "Certificate": "<base64-pfx>",
        "CertificatePath": null,
        "CertificatePassword": "<pfx-password>"
      },
      "TenantId": "my-tenant",
      "PushedAuthorizationBehavior": "UseIfAvailable",
      "RequestObject": {
        "Enabled": false,
        "SigningAlgorithm": "RS256",
        "Certificate": "<base64-pfx>",
        "CertificatePassword": "<pfx-password>",
        "KeyId": "my-request-object-key"
      },
      "UserScopes": "openid profile offline_access",
      "UserResources": "api://my-api"
    },
    "TlsCertificateValidation": {
      "AcceptAnyServerCertificates": false,
      "CustomTrustedRootCaFilePaths": [],
      "CustomTrustedTlsCertificatePaths": []
    },
    "DataProtectionSettings": {
      "ApplicationName": "MyBffApp",
      "Enabled": false
    },
    "BackChannelLogout": {
      "Enabled": false
    },
    "FrontChannelLogout": {
      "Enabled": true
    }
  }
}

General Settings ​

SettingTypeDefaultDescription
SessionTimeoutInMinutesint60Session idle timeout in minutes
PasswordChangeUrlClaimTypestring"pwchangeurl"Claim type for password change URL

Forwarded Headers ​

The BFF package configures ASP.NET Core ForwardedHeadersOptions from ProAuthBff:ForwardedHeaders. Host applications should still call app.UseForwardedHeaders() before authentication, authorization, session, antiforgery, and BFF endpoints.

SettingTypeDefaultDescription
ForwardedHeaders:UseForwardedHeadersbooltrueConfigures forwarded header processing options for BFF host applications
ForwardedHeaders:ForwardLimitint1Maximum number of forwarded header entries processed from each header
ForwardedHeaders:KnownProxiesstring""Comma-separated trusted proxy IP addresses
ForwardedHeaders:KnownNetworksstring""Comma-separated trusted proxy CIDR ranges

Back-Channel Logout ​

The BFF can receive OpenID Connect Back-Channel Logout notifications on POST /bff/backchannel-logout. This is optional and disabled by default.

json
{
  "ProAuthBff": {
    "BackChannelLogout": {
      "Enabled": true
    }
  }
}

When enabled, configure the client application in ProAuth with backchannel_logout_uri set to the public BFF endpoint, for example https://app.example.com/bff/backchannel-logout, and set backchannel_logout_session_required to true for interactive browser clients.

The endpoint expects the standard form POST shape logout_token=<jwt>, validates the token against the ProAuth issuer metadata and signing keys, rejects tokens with a nonce, rejects replayed jti values until token expiry, and removes matching local BFF authentication sessions by sid when present or by sub for subject-only logout tokens. Use a shared ticket store and distributed cache provider for multi-instance deployments so every instance can find and remove sessions created by another instance and enforce replay protection across pods.

Front-Channel Logout ​

The BFF can also receive OpenID Connect Front-Channel Logout notifications on GET /bff/frontchannel-logout. This endpoint is enabled by default and can be disabled with:

json
{
  "ProAuthBff": {
    "FrontChannelLogout": {
      "Enabled": false
    }
  }
}

The endpoint validates the optional iss parameter against the configured authority, removes sessions matching sid, and signs out the current browser cookie when the current session matches the logout notification.

Authentication Settings ​

SettingTypeRequiredDescription
AuthoritystringYesProAuth server URL (e.g., https://auth.example.com)
ClientIdstringYesOAuth 2.0 client identifier
ClientSecretstringFor secret-based methodsOAuth 2.0 client secret
ClientAuthenticationMethodstringNoAuto, None, ClientSecretPost, ClientSecretBasic, ClientSecretJwt, PrivateKeyJwt, TlsClientAuth, or SelfSignedTlsClientAuth. Auto uses ClientSecretBasic when a secret is configured and None otherwise.
ClientAssertion.SigningAlgorithmstringNoSigning algorithm for PrivateKeyJwt; defaults to RS256.
ClientAssertion.CertificatestringFor PrivateKeyJwt unless CertificatePath is setBase64 encoded PFX containing the assertion signing private key.
ClientAssertion.CertificatePathstringFor PrivateKeyJwt unless Certificate is setFile path to a PFX containing the assertion signing private key.
ClientAssertion.CertificatePasswordstringNoPassword for the assertion signing PFX.
ClientAssertion.KeyIdstringNoJWT header kid; should match a key in the client's ClientAssertionSigning key set.
ClientAssertion.LifetimeInSecondsintNoJWT client assertion lifetime; defaults to 60 seconds.
MutualTls.CertificatestringFor mTLS unless CertificatePath is setBase64 encoded PFX presented to ProAuth for TlsClientAuth or SelfSignedTlsClientAuth.
MutualTls.CertificatePathstringFor mTLS unless Certificate is setFile path to a PFX presented to ProAuth for mTLS.
MutualTls.CertificatePasswordstringNoPassword for the mTLS client certificate PFX.
SecurityProfilestringNoSet to Fapi2SecurityProfile to require the BFF-side FAPI 2.0 baseline.
SenderConstrainedTokenModestringNoNone, Dpop, or MutualTls.
Dpop.JsonWebKeystringNoPrivate JWK used for DPoP signing. When omitted, the BFF can generate an ephemeral process-local key.
TenantIdstringNoProAuth tenant identifier
AdditionalAcrValuesstringNoAdditional ACR values for the authentication request
PushedAuthorizationBehaviorstringNoPAR behavior: UseIfAvailable, Disable, or Require. Defaults to UseIfAvailable.
RequestObject.EnabledboolNoEnables JWT-secured authorization requests (JAR) for browser authorization flows.
RequestObject.SigningAlgorithmstringNoAsymmetric request-object signing algorithm. Defaults to RS256.
RequestObject.CertificatestringWhen JAR is enabledBase64 encoded PFX containing the request-object signing private key.
RequestObject.CertificateInput.CertificatePathstringWhen JAR is enabled unless Certificate is setFile path to the request-object signing PFX.
RequestObject.CertificatePasswordstringNoPassword for the PFX certificate.
RequestObject.KeyIdstringNoJWT header kid; should match the key registered on the ProAuth client app.
AuthorizationRequestClaimsstringNoRaw OIDC claims request parameter JSON added to authorization requests.
UserScopesstringNoSpace-separated scopes for user authentication (default: openid profile offline_access)
UserResourcesstringNoSpace-separated resource identifiers
ServiceScopesstringNoScopes for service-to-service authentication
ServiceResourcesstringNoResources for service-to-service authentication

Route Configuration ​

Routes define how the BFF proxies requests to your backend APIs:

json
{
  "ProAuthBff": {
    "Routes": [
      {
        "RouteId": "api-route",
        "Path": "/api/{**catch-all}",
        "Destination": "https://api.example.com",
        "InjectToken": true,
        "AccessTokenForwardingMode": "Automatic",
        "TransparentProxy": false,
        "RemoveRequestPrefix": true,
        "AuthorizationPolicy": "default"
      },
      {
        "RouteId": "public-route",
        "Path": "/public/{**catch-all}",
        "Destination": "https://api.example.com/public",
        "AllowAnonymous": true,
        "InjectToken": false
      }
    ]
  }
}

InjectToken=true remains a compatibility shortcut for bearer forwarding when SenderConstrainedTokenMode is None. It is rejected for DPoP- or mTLS-bound tokens because presenting a sender-constrained token as an ordinary bearer token is unsafe. New routes should use AccessTokenForwardingMode: "Automatic":

ModeBehavior
NoneNo access token is sent downstream.
BearerSends Authorization: Bearer <access_token>.
DpopSends Authorization: DPoP <access_token> and adds a DPoP proof for the proxied request.
MutualTlsSends Authorization: Bearer <access_token> through the configured mutually authenticated TLS connection.
AutomaticResolves to Bearer, Dpop, or MutualTls from SenderConstrainedTokenMode.

SenderConstrainedTokenMode is the only setting that activates DPoP. When SecurityProfile is Fapi2SecurityProfile, the BFF requires PAR, PKCE, secure client authentication, and either DPoP or mTLS sender-constrained tokens. Use AccessTokenForwardingMode: "Automatic" for routes that forward the access token obtained by the BFF so token acquisition and presentation cannot diverge.

The BFF validates route forwarding against the effective sender-constrained mode during startup. Explicit Bearer, Dpop, or MutualTls forwarding must match SenderConstrainedTokenMode; mismatches stop startup with a configuration error.

By default, BFF routes use API-client semantics. The downstream HTTP Host is derived from Destination, and the BFF removes inherited Forwarded, X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-Prefix headers. This prevents browser-facing origin metadata from making a forwarded-header-aware API reconstruct a URI different from the actual API destination. ResponsePrefixMode: "XForwardedHeader" remains an explicit exception that sends the configured X-Forwarded-Prefix only.

Set TransparentProxy: true only when the destination intentionally treats the BFF URL as its public origin and needs YARP's standard forwarded-host, scheme, prefix, and client-address behavior. Transparent proxy mode is rejected for DPoP routes because the proof is bound to the configured Destination URI rather than the browser-facing BFF URI.

Route Options ​

SettingTypeDefaultDescription
RouteIdstringRequiredUnique identifier for the route
PathstringRequiredURL pattern to match (supports {**catch-all} for wildcards)
DestinationstringRequiredBackend API base URL
InjectTokenboolfalseWhether to inject the access token as a Bearer token
AccessTokenForwardingModeenumNoneHow an injected access token is presented to the downstream API. Prefer Automatic for the token obtained by this BFF.
TransparentProxyboolfalseForward browser-facing origin and client metadata using YARP's default forwarded headers. Enable only for an intentional transparent reverse-proxy route; it is incompatible with DPoP forwarding.
AllowAnonymousboolfalseAllow unauthenticated requests
AuthorizationPolicystringnullASP.NET Core authorization policy name
RemoveRequestPrefixboolfalseRemove the matched path prefix when forwarding
PreventRedirectToLoginboolfalseReturn 401 instead of redirecting to login
CustomHeadersdict{}Custom headers to add to proxied requests
ResponsePrefixModeenumNoneHow to handle response URL prefixes
ResponseRewriteLinkHeadersboolfalseRewrite Link headers in responses
ResponseRewriteXPaginationHeaderboolfalseRewrite X-Pagination headers
RewriteManifestWithCredentialsboolfalseRewrite manifest files with credentials

TLS Certificate Validation ​

For development or private CA scenarios:

json
{
  "ProAuthBff": {
    "TlsCertificateValidation": {
      "AcceptAnyServerCertificates": false,
      "CustomTrustedRootCaFilePaths": [
        "/etc/ssl/certs/custom-ca.crt"
      ],
      "CustomTrustedTlsCertificatePaths": [
        "/etc/ssl/certs/custom-cert.crt"
      ],
      "EnableFileSystemWatcher": true
    }
  }
}

WARNING

Never set AcceptAnyServerCertificates to true in production environments.

Data Protection Settings ​

For multi-instance deployments, configure data protection to share authentication cookies:

json
{
  "ProAuthBff": {
    "DataProtectionSettings": {
      "ApplicationName": "MyBffApp",
      "Enabled": true,
      "EncryptionKeys": {
        "Mode": "X509",
        "Certificate": "BASE64_ENCODED_CERTIFICATE",
        "CertificatePassword": "certificate-password",
        "KeyRotationDecryptionCertificates": [
          {
            "Certificate": "BASE64_ENCODED_OLD_CERTIFICATE",
            "CertificatePassword": "old-password"
          }
        ]
      }
    }
  }
}

Token Store Providers ​

The BFF requires a token store to persist user tokens between requests. Choose the appropriate provider based on your deployment scenario.

In-Memory Token Store ​

Package: ProAuth.Oidc.Client.InMemory

Best for development, testing, and single-instance deployments.

csharp
builder.Services.AddBff(builder.Configuration)
    .WithInProcessLocking()
    .WithInMemoryTokenStore()
    .WithInMemoryTicketStore();

WARNING

In-memory storage does not survive application restarts and cannot be shared across multiple instances. Use only for development or single-instance scenarios.

Redis Token Store ​

Package: ProAuth.Oidc.Client.Redis

Recommended for production multi-instance deployments.

csharp
builder.Services.AddBff(builder.Configuration)
    .WithRedisLocking()
    .WithRedisTokenStore()
    .WithRedisTicketStore();

Configuration:

json
{
  "Redis": {
    "ConnectionString": "localhost:6379,password=secret"
  }
}

Dapr Token Store ​

Package: ProAuth.Oidc.Client.Dapr

For applications using Dapr for state management.

csharp
builder.Services.AddBff(builder.Configuration)
    .WithDaprLocking()
    .WithDaprTokenStore()
    .WithDaprTicketStore();

Requires Dapr state store component configuration.

ReaFx Token Store ​

Package: ProAuth.Oidc.Client.ReaFx

For applications built with the ReaFx framework.

csharp
builder.Services.AddBff(builder.Configuration)
    .WithReaFxLocking()
    .WithReaFxTokenStore()
    .WithReaFxTicketStore();

INFO

ReaFx integration is available separately for licensed ReaFx customers. Contact your account representative for more information.

Auth Session Token Store ​

Package: ProAuth.Oidc.Client.AspNetCore

Stores tokens in the server-side authentication ticket, with only a protected session reference in the browser cookie. A ticket store is required; cookie-only configuration is rejected when the cookie authentication options are initialized.

csharp
builder.Services.AddBff(builder.Configuration)
    .WithInProcessLocking()
    .WithAuthSessionTokenStore()
    .WithInMemoryTicketStore();

For multiple instances, use a shared Redis, Dapr, or ReaFx ticket store and its matching distributed lock provider on every instance. In-process locking and in-memory tickets are suitable only for a single instance.

Initial and refreshed tokens use the same 30-second refresh margin, while the ticket’s expires_at retains the actual access-token expiry. The token store reloads the authoritative session ticket after acquiring the refresh lock instead of relying on ASP.NET Core's request-cached authentication result. Token writes, sliding cookie renewal, and logout coordinate through the configured lock provider. A late response preserves newer tokens, and a refresh finishing after logout cannot recreate the removed session. A new sign-in establishes a new session generation so requests from the previous sign-in cannot overwrite its tokens or renew its old ticket. Separate sessions for the same user retain separate tokens.

When upgrading a cookie-only WithAuthSessionTokenStore() configuration, add a ticket store as shown above. The in-memory ticket store now returns independent ticket snapshots, matching distributed stores; mutate a retrieved ticket and call RenewAsync to persist a change.

Authentication Endpoints ​

The BFF package automatically registers authentication controllers:

EndpointMethodDescription
/signinGETInitiates OIDC login flow
/signoutGET/POSTSigns out the user
/signout-callback-oidcGETOIDC sign-out callback
/account/infoGETReturns current user information

Frontend Integration ​

Your SPA can check authentication status and user info:

typescript
// Check if user is authenticated
const response = await fetch('/account/info', {
  credentials: 'include'
});

if (response.ok) {
  const userInfo = await response.json();
  console.log('User:', userInfo);
} else if (response.status === 401) {
  // Redirect to login
  window.location.href = '/signin';
}

Advanced Configuration ​

Custom Token Processing ​

You can add custom processing when tokens are validated:

csharp
builder.Services.AddBff(builder.Configuration,
    configureAuthenticationOptions: options =>
    {
        options.CustomTokenProcessing = async (context, logger) =>
        {
            // Add custom claims or perform additional validation
            var identity = (ClaimsIdentity)context.Principal.Identity;
            identity.AddClaim(new Claim("custom_claim", "custom_value"));
            
            logger.LogInformation("Token validated for user {User}", 
                context.Principal.Identity.Name);
        };
    });

Programmatic Configuration ​

All configuration can also be done programmatically:

csharp
builder.Services.AddBff(
    builder.Configuration,
    configureBffOptions: options =>
    {
        options.SessionTimeoutInMinutes = 120;
        options.Routes.Add(new BffRouteOptions
        {
            RouteId = "api",
            Path = "/api/{**catch-all}",
            Destination = "https://api.example.com",
            InjectToken = true,
            TransparentProxy = false
        });
    },
    configureAuthenticationOptions: options =>
    {
        options.Authority = "https://auth.example.com";
        options.ClientId = "my-client";
        options.ClientSecret = "secret";
    });

Security Considerations ​

The BFF uses secure, HTTP-only cookies with the following defaults:

  • HttpOnly: Prevents JavaScript access
  • Secure: Only sent over HTTPS
  • SameSite=None: Required for cross-origin scenarios (OIDC flows)

CSRF Protection ​

MapProAuthBff() requires X-ProAuth-BFF: 1 on every proxied request except GET, HEAD, and OPTIONS. If an Origin header is present, it must match the BFF request's scheme and host. A missing intent header or a foreign origin returns HTTP 403 before token injection or forwarding. This protects cookie-authenticated proxy writes, including bodyless commands, from HTML form submissions and cross-origin scripts. Keep the BFF and SPA on the same origin and configure trusted forwarded headers before routing when TLS terminates at a reverse proxy.

typescript
fetch('/api/data', {
  method: 'POST',
  headers: { 'X-ProAuth-BFF': '1', 'Content-Type': 'application/json' },
  credentials: 'same-origin',
  body: JSON.stringify(data)
});

The React AdminApp supplies the header through its shared authenticatedFetch adapter. Other BFF consumers must add it to their API write transport. The header is an explicit browser intent marker, not an authentication token. Server authorization remains mandatory. OIDC callbacks and local MVC endpoints use their existing protocol/MVC protections; the proxy rule does not replace those protections.

Preventing Open Redirects ​

The BFF validates redirect URLs to prevent open redirect attacks. Only relative URLs and URLs to the configured authority are allowed.

Troubleshooting ​

Common Issues ​

401 Unauthorized on API calls

  • Verify the route has InjectToken: true
  • Check that the user is authenticated
  • Verify the access token hasn't expired

Cookie too large errors

CORS errors

  • The BFF should be served from the same origin as your SPA
  • Verify your reverse proxy or hosting configuration

Token refresh failures

  • Ensure offline_access scope is requested
  • Verify refresh tokens are enabled for your client in ProAuth

See Also ​

Browser sign-out confirmation ​

GET /bff/account/logout displays a confirmation form and leaves the session active. The form submits to POST /bff/account/logout, which requires a valid ASP.NET Core antiforgery token and accepts returnUrl as a form field. Existing sign-out links remain supported through the confirmation page. Do not automatically submit this page: confirmation prevents another site from terminating the browser session by navigating to the endpoint. OIDC front-channel and back-channel logout endpoints retain their protocol-specific validation.

Customize the confirmation page ​

Applications can supply an MVC Razor view to use their own branding, layout and translated text. Configure its name through ProAuthBff:LogoutConfirmationViewName or the existing AddBff callback:

csharp
builder.Services.AddBff(builder.Configuration, configureBffOptions: options =>
{
    options.LogoutConfirmationViewName = "~/Views/Account/Logout.cshtml";
});

Add the view to the host application's ASP.NET Core web project. AddBff already registers MVC view support. This is a controller view, so do not add an @page directive:

cshtml
@model ProAuth.Bff.Models.LogoutConfirmationViewModel
@{ Layout = "_Layout"; }

<h1>Sign out</h1>
<p>Confirm that you want to sign out of this application.</p>
<form method="post" action="@Model.LogoutAction" asp-antiforgery="false">
    <input type="hidden" name="returnUrl" value="@Model.ReturnUrl" />
    <input type="hidden" name="@Model.AntiforgeryFieldName" value="@Model.AntiforgeryToken" />
    <button type="submit">Sign out</button>
    <a href="@Model.ReturnUrl">Cancel</a>
</form>

Use your application's layout or set Layout = null and supply a complete HTML document. The BFF provides a path-base-aware LogoutAction, a validated local ReturnUrl, and the antiforgery field name and token. Use normal Razor expressions so values remain HTML-encoded. The example disables automatic form-tag-helper token generation because the model already supplies the token.

The custom view is rendered at the existing authenticated GET endpoint. It must require an explicit user action to POST; cancelling must only navigate. The BFF continues to validate antiforgery tokens and return URLs on POST, and sends Cache-Control: no-store and X-Frame-Options: DENY for the confirmation response.

Custom views use the host application's content security policy, including policies configured through AddBffSecurity. Permit the assets your layout needs, restrict form submission to trusted destinations, and disallow framing. The built-in page retains its restrictive policy. Leaving the view name unset or blank keeps the built-in page; a configured view that cannot be found produces an MVC view-resolution error.

ProAuth Administration uses this setting to share the branding and light/dark styling of its server error page without loading the SPA.