The strongest place is not the browser at all. RFC 10017, the IETF best current practice for browser based OAuth apps, ranks a backend for frontend (BFF) first: the server holds the tokens and the browser holds only a session cookie. If you must keep tokens in the browser, accept the risk knowingly.
The three patterns
RFC 10017, published in August 2026, lists three architectures in decreasing order of security.
| Pattern | Who holds tokens | Trade off |
|---|---|---|
| Backend for frontend (BFF) | The BFF server, tied to a cookie session | More to build and run |
| Token mediating backend | Backend gets tokens, hands access token to the app | Stolen access token still works |
| Browser based OAuth client | The browser app itself | Simplest, most exposed |
What a BFF does
The RFC gives the BFF three jobs. It acts as a confidential OAuth client toward the authorization server. It manages access and refresh tokens inside a cookie based session, so no token is exposed to the browser app. It forwards API requests to the resource server and adds the right access token on the way.
Because the tokens never reach the browser, a script injected into your page has no token to steal. The RFC says the BFF pattern is strongly recommended for business applications, sensitive applications, and applications that handle personal data.
It is not free. The RFC admits the BFF is significantly more complicated than a browser only app, and that proxying every API call adds load to server components.
Why not just use localStorage
The RFC is direct: localStorage does not protect against unauthorized access from malicious JavaScript, because the attacker's code runs in the same origin and can read the contents. It also persists across tabs and sessions, so a stolen refresh token can work for a long time. The RFC notes sessionStorage is tied to one tab, which slightly reduces exposure, and also describes in memory storage as an option. Neither removes the risk.
A decision guide
- Do you control a server that can sit in front of your APIs? Build a BFF.
- Do you handle personal or financial data? Treat the BFF as the default, per the RFC.
- No backend and no way to add one? Use the authorization code flow with PKCE, short lived access tokens, and refresh token rotation. Keep tokens in memory where you can, and accept that an XSS bug can still reach them.
- Whatever you pick, work on XSS prevention. A strict Content Security Policy and output encoding reduce the chance an attacker runs code in your origin.
Cookie settings for the BFF session
Because the BFF relies on a cookie session, treat that cookie as the crown jewel. Use the Secure and HttpOnly attributes and choose a SameSite value deliberately. The RFC also discusses server side versus client side sessions: server side sessions give you control and revocation, while signed client side sessions are easier to scale but harder to revoke.
Quick check
Is an HttpOnly cookie safer than localStorage for a session?
For reading the value, yes: scripts cannot read an HttpOnly cookie. But a script in your origin can still make requests that carry the cookie, so XSS remains a serious problem.
Does a BFF replace the need for PKCE?
No. RFC 9700 recommends PKCE even for confidential clients, and a BFF is a confidential client.
Safeguard's SBOM and dependency scanning shows which front end and auth libraries you ship and which have known advisories. There is a free scan if you want to try it on a repo.
Sources
- RFC 10017, OAuth 2.0 for Browser-Based Applications
- RFC 9700, Best Current Practice for OAuth 2.0 Security
Last reviewed: 19 October 2026.