The Backend for Frontend (BFF) pattern emerged in 2015 to cater to the needs of different clients and counter the idea of a general-purpose backend. Experiences showed that different clients have different requirements, which may necessitate backend services.

The goal is to achieve a division of responsibilities and make backends smaller and more maintainable.

Recently, the interpretation of the BFF concept has evolved. There is talk of accommodating cross-cutting concerns in a BFF, such as security. Personally, I have interpreted the pattern from a domain-oriented perspective. For cross-cutting aspects, terms like proxy or gateway feel more intuitive to me. It might help others to initially work with these terms.

Web frontends have been evolving steadily in recent years, departing from the original notion of a site provided by a single domain. The industry buzzwords include microservices and micro-frontends, which stem from the idea of decomposing systems, preferably based on domain-driven design. Distributed systems are not a new invention, but they were not the standard in the web environment. Progress has created remarkable possibilities. One milestone is likely the concept of module federation by Webpack. It allows dynamic composition of application parts at runtime within a single-page application. This enables new interaction options between application parts, as they now operate in a Window object in the browser (in contrast to iframe solutions). The core idea of microservices in the frontend is thus becoming a reality, and even I, as a backend developer, can achieve it (albeit with some effort).

Now, what are the consequences of this decomposition?

SPAs/frontends must allow cross-site communication.

Cross-site communication is also required in the cross-cutting domain. Customers want SSO (Single Sign-On), SLO (Single Logout), and user federation. Therefore, everything should still be interconnected and provide a good user experience. This led to the emergence of IAM (Identity and Access Management) systems, bringing along OAuth, OIDC, and SAML.

The token-based approach is currently the standard. This transition was driven by the fact that the session-based approach with cookies led to CSRF (Cross-Site Request Forgery) problems. The browser always sends the cookies, without any action required. Token mechanisms bypass this issue because the application controls the handling of access tokens. However, this has also created a new problem (Cross-Site Scripting). SPAs are public clients, and the content in the browser is not always secure by default.

There are approaches to mitigate this issue (such as closures or service workers). Service workers, originally derived from the concept of PWAs (Progressive Web Apps) and offline capabilities, operate based on a same-origin approach. They can intercept and enrich HTTP requests with authorization/authentication information in a separate thread with a separate memory space. However, there are also situations where JavaScript-based Spectre attacks can compromise the memory space.

One conclusion might be to move token management from the client to a server. After all, data that doesn’t reside on a system cannot be compromised.

Then the question remains: How do we handle AuthZ/AuthN (Authorization and Authentication) on the client side?

Sessions and cookies were avoided due to cross-site communication. Developments in browsers have introduced same-site, secure, and HTTPOnly cookies. If cross-site/cross-domain can be prevented, these cookies can be utilized. Hence, the BFF pattern (in this particular case, also referred to as Full-BFF) includes a proxy to the required services.

Therefore, a Full-BFF can be an option to address the issue of cross-site scripting through a security-by-design approach, and it should be considered for future projects. Another argument is the efforts by browser manufacturers to restrict or prohibit third-party cookies. Unfortunately, OAuth implementations in the context of session notification and silent renewals often use hidden iframes, which automatically involve third-party cookies. Of course, SLO aspects can also be addressed with backchannel-oriented implementations, although that is not always the case with all IAM products.

However, there is a catch. Same-site cookies have sandboxing applied to the site by default, not the origin (unlike the service worker).

Subdomain attacks can thus become a vulnerability. To mitigate this, CORS (Cross-Origin Resource Sharing) can be used. This involves enriching requests with a custom header, which forces the browser to make a preflight CORS request. On the server side, it only allows requests from trusted subdomains.

In summary:

When should one consider this topic? In all cases involving cross-site communication.

Of course, there are also drawbacks. The central component for the client may need individual treatment in terms of scalability, for example.

It is not a silver bullet. The decision to use it should be balanced against the data protection needs of the application, development efforts, operational efforts, and so on.

But it is a tool that should be known in 2023, especially since the IETF has issued it as a recommendation this year.

Sources

Token Management in SPAs:

  • Medium Article: “Frontend JWT Token Storage” Link
  • Curity Resources: “SPA Best Practices” Link
  • Grabyo: “Service Workers & JWT Tokens” Link

Service Worker:

  • MDN Documentation: “Service Worker API” Link

PWA (Progressive Web Apps):

  • MDN Documentation: “Progressive Web Apps” Link
  • Web.dev: “Progressive Web Apps” Link

SameSite Cookie:

  • Can I use: “Same-Site Cookie Attribute” Link

“Cookie Apocalypse” - Third-Party Cookies in Browsers:

  • WebKit Blog: “Full Third-Party Cookie Blocking and More” Link
  • The Verge Article: “Google delays Chrome’s cookie-blocking privacy plan” Link

Module Federation:

  • Webpack Documentation: “Module Federation” Link
  • Heise Article: “Die Micro-Frontend-Revolution - Webpack 5 Module Federation” Link

CORS Preflight:

  • MDN Documentation: “Cross-Origin Resource Sharing (CORS) - Preflighted Requests” Link
  • Book: “CORS in Action” Link

Spectre in Service Workers:

  • Security Stack Exchange: “Does enabling SharedArrayBuffers via Service Worker headers create Spectre vulnerability?” Link

Security BFF:

  • JetBrains Blog: “Securing SPAs and Blazor applications using the BFF pattern” Link

BFF in the original sense:

  • Microsoft Azure Architecture Patterns: “Backends for Frontends” Link
  • Sam Newman (Author of the pattern): Link

IETF Recommendation:

  • IETF Document: “OAuth 2.0 for Browser-Based Apps” Link
  • TMI-BFF (reduced variant) is based on: “The OAuth 2.0 Authorization Framework: Bearer Token Usage” Link

Don’t forget this recommendation: Authorization Code Flow with PKCE:

  • WSO2 Blog: “Securing SPAs: Best Practices” Link

HOW TO DO IT??

  • GitHub: “DuendeSoftware/BFF” Link

Apache-based:

  • Blog: “OpenID Connect for Single-Page Applications” Link
  • GitHub: “OpenIDC/mod_auth_openidc Wiki - Single-Page Applications” Link