Breaking & Securing OAuth 2.0 in Frontends • Philippe De Ryck • YOW! 2025
This talk by Philippe De Ryck explains why common OAuth 2.0 patterns in Single Page Applications (SPAs) are fundamentally insecure against Cross-Site Scripting (XSS) attacks. He demonstrates how defenses like refresh token rotation can be bypassed and introduces the Backend-for-Frontend (BFF) pattern as the secure, recommended solution.
The Inherent Insecurity of Browser-Based OAuth 2.0
Implementing OAuth 2.0 directly in browser-based applications, such as Single Page Applications (SPAs), significantly increases the application’s attack surface. The primary threat is Cross-Site Scripting (XSS), an attack where a malicious actor injects and executes JavaScript in the context of the application. While XSS is a well-known vulnerability, its impact is amplified in modern front-ends where sensitive tokens are managed directly in JavaScript.
An attacker who achieves XSS in an SPA can steal OAuth tokens (access and refresh tokens) from browser storage (e.g., Local Storage, Session Storage) or memory. These tokens can then be used to access protected APIs on behalf of the user, leading to a complete compromise of the user’s session.
Debunking Common Mitigation Strategies
Two common defenses are often proposed to secure browser-based OAuth flows, but both are fundamentally flawed when facing a determined attacker.
1. Refresh Token Rotation
Refresh Token Rotation is a mechanism where a refresh token can only be used once. Upon use, the authorization server issues a new access token and a new refresh token, invalidating the old one. The server can then detect if an old, already-used token is presented again, signaling a potential breach and allowing it to revoke the entire token family.
However, this defense is easily sidestepped. A sophisticated attacker will not simply use a stolen token and wait to be caught. Instead, the malicious script can:
- Steal the latest refresh token and delete it from the browser’s storage, ensuring the legitimate application can never trigger the reuse detection.
- Monitor the user’s activity and wait for them to go offline before using the stolen token, taking over the session indefinitely.
This makes refresh token rotation a form of “security theater” that provides a false sense of security against real-world attack scenarios.
2. “Hiding” Tokens in the Browser
Another approach is to try and store tokens in a way that is inaccessible to JavaScript. The fundamental problem here is that the legitimate application’s JavaScript needs access to the tokens to function.
Even if a perfectly secure storage mechanism existed in the browser, a more severe vulnerability remains. Malicious JavaScript running in the application’s context can initiate a new, silent OAuth 2.0 flow in a hidden iframe. Since the user likely has an active session with the authorization server (managed by a cookie), the server will seamlessly issue a new authorization code to the compromised front-end. The attacker’s script can intercept this code, exchange it for a completely fresh and independent set of tokens, and gain its own persistent access to the user’s data.
The Superior Solution: The Backend-for-Frontend (BFF) Pattern
The core issue is that browser-only flows are inherently insecure because the final step—delivering the authorization code—occurs in an environment that can be compromised by XSS. The most robust solution is to move the OAuth 2.0 client logic out of the browser and into a trusted, server-side component using the Backend-for-Frontend (BFF) pattern.
In this architecture:
- The BFF is the OAuth Client: The BFF, a backend service dedicated to the front-end, becomes the confidential OAuth 2.0 client. It securely stores a client secret and manages all token interactions with the authorization server.
- Tokens Remain on the Server: Access and refresh tokens are never sent to or stored in the browser. They live exclusively within the BFF.
- Session Management via Secure Cookies: The front-end maintains a session with the BFF using a secure,
HttpOnly,SameSitecookie. This cookie is inaccessible to JavaScript, mitigating theft via XSS. - API Calls are Proxied: When the front-end needs to call a protected API, it sends a request to the BFF. The BFF validates the session cookie, retrieves the corresponding access token, attaches it to the request, and proxies the call to the downstream API. The BFF also handles token refreshing transparently.
With a BFF, the security model becomes equivalent to that of a traditional, server-side web application, effectively eliminating the token theft and session hijacking vulnerabilities present in browser-only flows. While XSS should still be prevented, its impact is dramatically reduced; an attacker can only make requests to the endpoints exposed by the BFF, not steal the underlying tokens for unrestricted API access.
Key Takeaways
- Do not use OAuth 2.0 directly in the browser. It significantly and unnecessarily increases your attack surface.
- Adopt the BFF pattern. It simplifies the front-end by removing complex security logic and provides a robust, server-side security posture.
- Continue to prevent XSS. Even with a BFF, secure coding guidelines are essential to protect the user’s interaction with the application.