YouMind
Sign in

Moving Tokens Out of the Browser with the BFF Pattern

@farstep_
JAPANESEJun 01, 2026
295K
604
38
0
1.1K

TL;DR

This article explains how the BFF pattern secures SPA applications by handling OAuth tokens on the server side and using HttpOnly cookies, significantly reducing the impact of XSS vulnerabilities.

When handling OAuth in a Single Page Application (SPA), where to store access and refresh tokens has been a long-standing debate. localStorage, sessionStorage, and in-memory variables are all insufficient against XSS. The Backend for Frontend (BFF) pattern is a design where tokens are held on the server side instead of being passed to the browser. This article organizes the mechanism and key implementation points.

Prerequisites

This article assumes the following environment:

  • Development of a browser-based app using OAuth 2.0 and OpenID Connect.
  • Existence of an SPA, the APIs it calls, and an authorization server.
  • The SPA and its supporting server-side components can be placed on the same parent domain.
  • HTTPS is a prerequisite (required for issuing Secure Cookies).

XSS Risks in Browser-Based Apps

Application code running in the browser is vulnerable to everything that happens in the browser's execution environment. XSS has a wide impact, and because attack code runs in the same context as the app, the following operations are possible:

  • Reading values stored in localStorage or sessionStorage.
  • Reading in-memory variables accessible from JavaScript.
  • Executing all API calls the app can perform.
  • Changing behavior by overwriting built-in functions (prototype pollution).

There are multiple entry points for XSS, such as vulnerabilities in dependent libraries, flaws in input/output processing of your own code, or compromise of third-party scripts. Since it is difficult to completely prevent XSS, a realistic policy is to "limit the impact if an intrusion occurs."

As long as tokens are placed in the browser, the possibility of tokens being stolen via XSS remains. If an attacker uses a stolen refresh token in their own environment, they can call APIs for a long time even after the user closes the website. While token rotation and idle timeouts can mitigate the impact, they are not fundamental solutions.

Design That Doesn't Place Tokens in the Browser

The BFF pattern provides a server-side component dedicated to the SPA and centralizes OAuth client responsibilities there. The SPA does not handle OAuth processing directly but performs authentication and API calls via the BFF.

The division of roles is as follows:

  • OAuth protocol communication with the authorization server: Handled by the BFF.
  • Holding access and refresh tokens: BFF only.
  • Maintaining authentication state between SPA and BFF: HttpOnly Cookie.
  • API calls: The SPA sends requests to the BFF, and the BFF converts the Cookie into a token and forwards it to the API.

In this configuration, tokens only circulate between the BFF and the APIs it calls, and are invisible to the browser's JavaScript. Even if XSS occurs, an attacker cannot extract the token and use it from elsewhere. All an attacker can do is send requests to the BFF within the scope of the session currently open by the user. While this impact is not negligible, the duration and scope of the impact are significantly limited compared to token theft.

The BFF acts as what OAuth terminology calls a "confidential client." It holds a client secret and completes the exchange of authorization codes for tokens and refresh processing entirely on the server side.

Authentication Flow

A typical authentication flow is as follows:

farstep on X — cover
  1. When the SPA starts a login, it sends a login request to the BFF.
  2. The BFF starts an authorization code flow with PKCE, generates a redirect URL to the authorization server, and returns it to the SPA.
  3. SPA transitions the browser to that URL, and the user authenticates at the authorization server.
  4. The authorization server returns an authorization code to the BFF's redirect URI.
  5. The BFF exchanges the authorization code for tokens and obtains an access token and a refresh token.
  6. The BFF stores the tokens in its own secure area (encrypted cookie, server-side session store, etc.) and returns only a session identifier to the SPA via an HttpOnly Cookie.
  7. When the SPA calls an API, it sends the request via the BFF. The Cookie is sent simultaneously, and the BFF converts it into an access token and forwards it to the upstream API.
  8. If the access token expires, the BFF silently updates it using the refresh token.

From the SPA's perspective, the login state is maintained by the Cookie, and API requests are completed with normal fetch calls. Code that directly handles OAuth tokens or authorization codes does not exist in the SPA.

Required Security Settings

The following attributes must be set for the Cookie issued by the BFF:

  • HttpOnly: Prohibits access from JavaScript. Even with XSS, the Cookie contents cannot be read.
  • Secure: Sent only over HTTPS.
  • SameSite=Strict: Ensures the Cookie is not sent with requests from other sites. This helps block major CSRF attack paths, but CSRF protection is not completed by this alone.
  • __Host- prefix: Adding the __Host- prefix to the Cookie name ensures the browser limits the Cookie to the issuing host and does not share it with subdomains.

If storing tokens in an encrypted Cookie (client-side session), the Cookie content is encrypted. If placing tokens in a server-side session store (server-side session), the Cookie only contains a session identifier, so encryption is not necessary.

CSRF Protection Should Not Rely Solely on SameSite

Since it uses Cookie-based authentication, the BFF must implement protection against CSRF. SameSite=Strict is a valid step, but not the entire solution. Caution is especially needed in configurations where the SPA is placed on www.example.com and the BFF on api.example.com. Since SameSite determination is done by site rather than origin, requests from other subdomains under example.com are considered "same-site," and Cookies will be sent even with SameSite=Strict.

Therefore, reinforce CSRF defense with one of the following:

  • If the BFF and SPA are on different origins, use CORS and Origin header validation for defense.
  • For requests that change state, verify CSRF tokens using the anti-forgery / double-submit cookie method.

Limit CORS to Exact Origins

CORS should be permitted only for the exact origin of the SPA. For credentialed requests involving Cookies, browsers do not allow wildcards (*) in Access-Control-Allow-Origin. Therefore, the BFF must reflect the exact origin of the SPA in the response. This strictly limiting permitted origins functions as part of the CSRF defense.

Key management is required for session data held by the BFF, especially token information stored in encrypted Cookies. Incorporate operations to securely inject keys as BFF settings and rotate them regularly.

Note that placing the SPA and BFF on the same parent domain is to satisfy the condition for Same-Site Cookies to function as first-party Cookies.

Evolution: API-Driven BFF

If a BFF is built like a traditional web app, the BFF's server-side rendering becomes involved in the SPA's page transitions. An API-driven BFF minimizes this impact.

The roles are divided into two:

  • OAuth Agent: An API responsible for OAuth protocol processing. It is called from the SPA via JSON.
  • OAuth Proxy: Operates as an API gateway plugin, extracts the token from the Cookie, and forwards it to the upstream API.

In this configuration, the SPA simply calls the OAuth Agent as a normal REST API. The SPA frontend development experience can be kept almost the same as before introducing the BFF.

Considerations for Adoption

When adopting the BFF pattern, consider the following:

  • Additional architectural components increase development and operation costs.
  • The SPA and BFF must be placed on the same parent domain.
  • A configuration that simply forwards the Authorization header via a reverse proxy is not a BFF. The essence of a BFF is holding the token as a confidential client.
  • PKCE and BFF are used together, not as alternatives.
  • The BFF must verify the destination host before forwarding to prevent token exposure to unintended hosts.
  • Logout design becomes complex as SPA sessions, BFF cookies, and authorization server sessions must all be linked.

Summary

A practical way to handle tokens safely in browser-based apps is to not place them in the browser. The BFF pattern moves OAuth client responsibilities to the server side and passes only HttpOnly Cookies to the browser. This prevents token theft even if XSS occurs. By dividing roles into an OAuth Agent and OAuth Proxy, security can be strengthened while maintaining the SPA development experience.

One-click save

Use YouMind for AI deep reading of viral articles

Save the source, ask focused questions, summarize the argument, and turn a viral article into reusable notes in one AI workspace.

Explore YouMind
For creators

Turn your Markdown into a clean 𝕏 article

When you publish your own long-form writing, images, tables, and code blocks make 𝕏 formatting painful. YouMind turns a full Markdown draft into a clean, ready-to-post 𝕏 article.

Try Markdown to 𝕏

More patterns to decode

Recent viral articles

Explore more viral articles