Choosing the Boundary: A Practical RFC 10017 Decision
The answer to “where should browser OAuth tokens live?” is a choice about authority, not a winner among browser storage APIs. RFC 10017 provides a practical ordering: make the OAuth client and token operations server-side when the application can accept a Backend for Frontend; in the server-side session form, the tokens remain on the server, while a client-side session requires protected cookie state; consider token mediation when direct resource-server calls are a genuine requirement; and use a browser-only client only when its residual exposure is acceptable. This conclusion brings together the request path, credential lifecycle, protocol requirements, and limits that a responsible design must state plainly.
The decision begins with the request boundary
Start with the operation the frontend needs to perform, not with the credential it already has. A browser application can appear to need “an access token” simply because its current implementation calls a resource server directly. That is an implementation path, not necessarily a system requirement. The more consequential question is whether the protected request must leave the browser directly or can pass through a server component that owns the OAuth relationship.
There is one important preliminary branch. If a frontend and API are first-party components on a common domain, OAuth may not be needed to govern access between them. The application can use ordinary server-side cookie session state after authenticating the user. OpenID Connect may still delegate federated authentication to a dedicated provider, but the frontend-to-backend relationship can remain a session relationship rather than becoming a second OAuth token exchange. RFC 10017 describes this as a way to avoid making a simple application needlessly complex.
That is not an argument against OAuth in every common-domain deployment. Retaining OAuth can provide future flexibility if another domain will later be added, allow reuse of established libraries, centralize login and multifactor authentication, or separate authentication from resource serving. The decision is whether OAuth is solving a real cross-party or cross-domain authorization problem, rather than being used as a fashionable replacement for session management. A same-domain session and federated login can coexist without putting an access token into the frontend merely to call the application’s own API.
If OAuth is required, ask whether the protected resource requests can be proxied through a backend. When the answer is yes, the BFF is the strongest default supported by the supplied evidence. RFC 10017 strongly recommends it for business applications, sensitive applications, and applications handling personal data. The reason is concrete: the BFF is the confidential OAuth client, performs token operations behind the server boundary, and translates a browser session into a request to an approved resource server. With a server-side session, the access and refresh tokens remain on the server; a client-side session may carry signed, optionally encrypted token material in a protected cookie, without exposing it to frontend JavaScript. The browser does not need to possess the OAuth tokens as credentials for direct resource-server calls or the credentials used to redeem an authorization code.
A BFF does spend infrastructure and operational capacity to retain that boundary. Every protected request and response passes through it. The component must handle session state, refresh behavior, CSRF defense, outbound destination controls, and appropriate rate-limiting assumptions. It also sees the traffic it proxies, which creates a privacy consideration if it is supplied or hosted by a third party. Those costs are not accidental flaws; they are the price of keeping authority and request translation on a component that can be treated as a confidential client.
If direct browser-to-resource-server calls are genuinely required, the next question is whether the refresh authority can remain server-side. If it can, a token-mediating backend is the middle position described by RFC 10017. The backend performs the Authorization Code flow as a confidential client and retains the refresh token with the session, but returns an access token to the browser. The frontend can then call the resource server directly. This avoids a full proxy, but it deliberately exposes access authority to the public browser runtime.
Token mediation is justified by a constraint that matters enough to accept that exposure. It should not be selected merely because a proxy seems inconvenient or because a team wants to avoid thinking about BFF routing. The direct-call requirement must be weighed against the attacks that access-token exposure enables. Malicious code can steal the access token, persistently collect renewed values, and use the token against a resource server. It can also ask the token mediator for a fresh access token through the user’s session. The backend still protects the refresh token and prevents the frontend from impersonating the confidential backend at the authorization server, but it does not recreate the BFF’s access-token boundary.
If refresh authority cannot stay server-side, the remaining option is a browser-only OAuth client. This can be appropriate for a public application whose requirements and threat model accept the browser’s possession of access credentials. It is not appropriate to describe that client as confidential, even if a static secret is included in the JavaScript bundle or hidden behind an obfuscation layer.