The Backend-for-Frontend (BFF) Pattern with Keycloak
Tokens are safest when they never touch a browser at all. The BFF pattern is the architectural sleight of hand that keeps Keycloak's tokens locked away on a server, while the browser only ever holds a humble, ordinary cookie.
Imagine a diplomat who never carries sensitive government documents in their own briefcase while traveling through public spaces. Instead, a secure courier holds every document at the embassy, and the diplomat simply carries a small, verifiable badge proving who they are — if the badge is ever lost or stolen, it identifies the diplomat but reveals nothing of substance and can be instantly deactivated. Modern browser-based applications face a strikingly similar problem: OAuth access and refresh tokens are powerful, sensitive credentials, and a browser — full of third-party scripts, extensions, and potential cross-site scripting vulnerabilities — is a genuinely risky place to store them directly. The Backend-for-Frontend (BFF) pattern is the architectural answer: introduce a dedicated server-side component that holds Keycloak’s tokens on the diplomat’s behalf, while the browser itself carries nothing more sensitive than a simple, well-protected session cookie. This guide, aimed at readers already comfortable with OAuth and OpenID Connect concepts, explains why the BFF pattern exists, how it’s architected around Keycloak specifically, what happens internally on every request, and how real teams design, secure, and operate it in production. No prior background in the BFF pattern itself is assumed.
1Core Concepts
The traditional single-page application token problem
A conventional single-page application (SPA) talking directly to Keycloak typically ends up holding an access token, and often a refresh token, somewhere in the browser — in memory, in local storage, or in a JavaScript-accessible cookie. Every one of these storage locations shares a common weakness: any malicious JavaScript running on that page, whether injected through a cross-site scripting vulnerability or hidden inside a compromised third-party library, can potentially read and exfiltrate those tokens. Modern web applications routinely load dozens of third-party scripts — analytics, advertising, customer support widgets — each one a potential avenue for exactly this kind of compromise.
What does the BFF pattern actually change?
The Backend-for-Frontend pattern introduces a dedicated server-side application, sitting between the browser and both the identity provider (Keycloak) and any backend APIs, that performs the OAuth/OpenID Connect login flow on the browser’s behalf, and holds the resulting tokens entirely on the server. The browser itself never receives the access or refresh token at all — instead, it receives a simple, traditional session cookie (ideally marked HttpOnly, meaning JavaScript cannot read it even if it wanted to), which the BFF uses to look up the corresponding tokens on its own server-side storage for every subsequent request.
Think of a hotel’s valet parking service. Instead of handing your car keys to every restaurant, gym, and shop you visit during your stay, you hand your keys once to the valet, who locks them securely in the hotel’s own key room. From then on, you simply show your claim ticket wherever you need your car — a claim ticket that, on its own, is useless to anyone who doesn’t also have access to the hotel’s locked key room. The BFF plays the role of that valet: it holds the actual “keys” (tokens), while the browser carries only a claim ticket (the session cookie).
Why is a cookie considered safer here than a token?
A well-configured session cookie — HttpOnly, marked Secure, with an appropriate SameSite attribute — is inaccessible to JavaScript entirely, meaning even a successful cross-site scripting attack cannot simply read it out of the page and exfiltrate it, unlike a token sitting in local storage or an ordinary, script-readable cookie. This doesn’t make the browser side of the application invulnerable to every possible attack, but it removes an entire, historically very common class of token theft that plagues traditional SPA architectures relying on direct, browser-held tokens.
Any organization building a modern single-page or mobile-web application against Keycloak that’s concerned about token exposure through cross-site scripting or third-party script risk, and any team whose security review has flagged direct browser-held tokens as a concern, is a natural candidate for adopting the BFF pattern.
Key vocabulary, explained simply
Backend-for-Frontend (BFF)
A dedicated server-side component, specific to a given frontend, that performs the OAuth login flow and holds tokens on the browser’s behalf.
Confidential Client
A Keycloak client type capable of securely holding a client secret, appropriate for the BFF itself since it runs entirely server-side.
HttpOnly Cookie
A cookie attribute preventing JavaScript from reading its value, a core building block of the BFF’s browser-facing session mechanism.
Token Vault / Server-Side Session Store
Wherever the BFF actually stores the real access and refresh tokens, keyed by the session identifier represented in the browser’s cookie.
Proxying / Token Injection
The BFF’s role in attaching the real access token to outgoing API requests on the browser’s behalf, since the browser itself never holds it.
Cross-Site Request Forgery (CSRF)
An attack the BFF pattern must explicitly defend against, since moving to cookie-based sessions reintroduces this classic web security concern.
2Standards, Protocols & the OAuth Client Role
The BFF as a confidential OAuth client
From Keycloak’s own perspective, the BFF is registered as a standard confidential client — a client type that can securely hold a client secret because, unlike a browser-based SPA, it runs entirely on infrastructure the organization controls. This is a meaningful protocol-level distinction: a confidential client can use the full Authorization Code flow with a genuine client secret, generally considered a stronger configuration than the public-client patterns (with PKCE substituting for a secret) that a browser-based application would otherwise need to use on its own.
Where the authorization code flow actually happens
The entire OAuth Authorization Code exchange — redirecting to Keycloak, the user authenticating, Keycloak redirecting back with an authorization code, and that code being exchanged for tokens — happens entirely between the BFF and Keycloak, with the browser only ever seeing ordinary web page redirects, never the tokens themselves. This is a direct, deliberate application of the standard flow, simply relocated so that the party holding the resulting tokens is a trusted, server-side component rather than the browser.
Think of a corporate travel agent who books flights and hotels on an employee’s behalf using the company’s own trusted account, rather than requiring each employee to somehow independently prove their corporate identity to every airline and hotel directly. The employee just tells the travel agent what they need; the travel agent handles the actual credentialed transactions, using access the employee never personally has to hold or manage. The BFF plays exactly this intermediary role between the browser and Keycloak.
Why this configuration is considered a best practice, not just one option among many
Current OAuth security guidance increasingly favors keeping tokens out of browser-accessible JavaScript contexts entirely, precisely because of the exfiltration risks discussed in the previous chapter. The BFF pattern is a direct, architecturally clean way to satisfy this guidance without abandoning a rich, single-page application user experience — the frontend still feels and behaves like a modern SPA, but the actual OAuth mechanics happen in a location fundamentally safer than the browser.
Adopting the BFF pattern doesn’t mean the browser-facing side of the application is now exempt from web security fundamentals — the BFF’s own session cookie mechanism still needs careful protection against cross-site scripting (which could still hijack the session indirectly, even without directly reading tokens) and cross-site request forgery, discussed further in the security chapter.
Authorization Code Flow
The standard OAuth flow the BFF performs with Keycloak, relocated entirely to the server side rather than the browser.
Confidential Client Registration
How the BFF itself is registered in Keycloak, distinct from how a public, browser-based client would be configured.
PKCE (Proof Key for Code Exchange)
Still a recommended defense-in-depth addition even for a confidential client, protecting the authorization code exchange itself.
Session-to-Token Mapping
The BFF’s own internal mechanism linking a browser’s cookie-identified session to the corresponding, securely stored tokens.
3Architecture & Components
graph TB
B[Browser / SPA] -->|HttpOnly session cookie| BFF[Backend-for-Frontend]
BFF -->|Authorization Code flow| KC[Keycloak]
KC -->|Access + Refresh Tokens| BFF
BFF --> TS[Server-Side Token Store]
BFF -->|injects access token| API[Backend APIs]
B -->|API requests via cookie| BFF
BFF -->|proxies request + token| API
Component breakdown
The BFF Application Itself
A server-side application, typically deployed alongside or near the frontend, responsible for the OAuth flow, session management, and API request proxying.
Server-Side Token/Session Store
Where the BFF actually persists tokens, keyed to a session identifier — could be an in-memory store for a single instance, or a shared, distributed store for a horizontally scaled BFF deployment.
Keycloak’s Confidential Client Registration
The realm client configuration representing the BFF itself, including its client secret and allowed redirect URIs.
API Proxying/Gateway Logic
The BFF’s mechanism for forwarding browser-originated requests to backend APIs, attaching the appropriate access token along the way.
Where this is configured relative to Keycloak
Inside the Keycloak Admin Console, the BFF is registered as an ordinary confidential client, with its client authentication enabled and its redirect URIs pointed at the BFF’s own callback endpoint — not at the frontend’s client-side routes, since the entire authorization code exchange happens server-side within the BFF itself, never in the browser.
A common real setup
A company builds a single-page application frontend and pairs it with a lightweight BFF service deployed alongside it, registered in Keycloak as a confidential client. The frontend makes ordinary, same-origin API calls to the BFF, which transparently handles the underlying OAuth session, attaches the real access token when forwarding requests to backend APIs, and refreshes tokens automatically and invisibly as needed — the frontend code itself never directly interacts with Keycloak’s token endpoints at all.
Why is horizontal scalability an architectural consideration here specifically?
Because the BFF holds session-to-token mappings, running more than one instance of it — necessary for handling real production load and providing redundancy — requires that server-side token store to be shared and consistent across instances, exactly analogous to how a clustered Keycloak deployment itself needs a shared session store. A BFF architecture that stores tokens only in a single instance’s local memory will break the moment a user’s requests are load-balanced across multiple BFF instances that don’t share that state.
4Internal Working
What happens during initial login
When an unauthenticated user reaches the frontend, the BFF detects the absence of a valid session cookie and initiates the standard OAuth Authorization Code flow itself — redirecting the browser to Keycloak’s login page. Once the user authenticates and Keycloak redirects back with an authorization code, this redirect lands on the BFF’s own server-side callback endpoint, not on any frontend JavaScript route. The BFF exchanges the code for tokens directly with Keycloak, server-to-server, stores the resulting tokens in its token store under a newly generated session identifier, and sets an HttpOnly cookie containing that session identifier in the browser’s response.
What happens on every subsequent API request
For every request the frontend makes to what it believes is “the API,” it’s actually calling the BFF, which reads the session cookie automatically included by the browser, looks up the corresponding access token from its server-side store, and forwards the request onward to the actual backend API with that token correctly attached — typically as a standard bearer token in an Authorization header. The response is then relayed back to the frontend. From the frontend’s own code perspective, it’s simply making ordinary, same-origin API calls; the entire token-handling machinery is invisible to it.
Handling token refresh transparently
Because the BFF holds the refresh token as well, it can detect an expiring or expired access token and silently refresh it using the standard OAuth refresh flow, entirely on the server side, without the browser or frontend code needing to be aware this happened at all. This is a meaningful usability improvement over traditional SPA token handling, where the frontend itself typically needs its own logic to detect and handle token expiry and refresh.
Because the frontend has no direct visibility into the underlying tokens or their expiry, a BFF implementation needs its own clear mechanism for signaling to the frontend when a session has genuinely, unrecoverably expired (for example, the refresh token itself has expired) versus when a request simply failed for an unrelated reason — without this, a frontend can be left confused about whether to prompt the user to log in again.
Step-by-step: a full BFF-mediated request cycle
Frontend makes an API call
The browser sends a request to what appears to be an API endpoint, with its session cookie automatically included.
BFF receives and identifies the session
The BFF reads the cookie, validates it, and looks up the corresponding stored tokens.
Token freshness checked
If the access token is expired or near expiry, the BFF silently refreshes it using the stored refresh token.
Request forwarded with token attached
The BFF forwards the original request to the actual backend API, attaching the valid access token.
API responds
The backend API processes the request normally and returns its response to the BFF.
BFF relays the response
The BFF passes the API’s response back to the frontend, completing the cycle transparently.
5Data Flow & Lifecycle
sequenceDiagram
participant Browser
participant BFF
participant Keycloak
participant API as Backend API
Browser->>BFF: Initial page load, no session cookie
BFF->>Keycloak: Redirects for login (Authorization Code flow)
Browser->>Keycloak: User authenticates
Keycloak->>BFF: Redirects back with authorization code
BFF->>Keycloak: Exchanges code for tokens (server-to-server)
Keycloak-->>BFF: Access + Refresh Tokens
BFF->>BFF: Stores tokens, generates session ID
BFF-->>Browser: Sets HttpOnly session cookie
Browser->>BFF: Subsequent API call (cookie only)
BFF->>API: Forwards request with real access token
API-->>BFF: Response
BFF-->>Browser: Relays response (no token ever exposed)
Notice, across this entire diagram, that the word “token” never appears on any arrow touching the browser directly — the browser’s involvement begins and ends with ordinary redirects and a simple cookie. This complete separation is the architectural core of the BFF pattern’s security value: there is simply no token present in the browser’s JavaScript context at any point for a cross-site scripting attack to steal.
The lifecycle of a BFF-managed session
Established at login
The initial OAuth flow completes, tokens are stored server-side, and the browser receives its session cookie.
Maintained through active use
Tokens are silently refreshed by the BFF as needed, keeping the underlying session alive without any frontend involvement.
Ended by logout or expiry
A user-initiated logout, or an eventual refresh token expiry, ends the session — the BFF clears its server-side token record and invalidates the cookie.
Frontend redirected to re-authenticate
Once the session genuinely ends, the frontend is signaled clearly, and the BFF initiates a fresh login flow the next time it’s needed.
Because the BFF’s session and Keycloak’s own underlying session are related but distinct concepts, a logout initiated through the BFF should also properly end the corresponding Keycloak session (and ideally trigger any relevant single sign-out behavior toward other applications), rather than merely clearing the BFF’s own local cookie and token record while leaving the Keycloak session itself still technically active.
6Advantages, Disadvantages & Trade-offs
Advantages
- Removes tokens from the browser’s JavaScript-accessible context entirely, closing off an entire class of token exfiltration risk
- Allows the frontend to use a confidential client’s stronger authentication configuration, rather than a public client’s more limited options
- Simplifies frontend code considerably, since token storage, refresh, and attachment logic all move server-side
- Provides a natural place to implement additional server-side security controls, like consistent CSRF protection and request logging
Disadvantages & Trade-offs
- Introduces an entirely new server-side component that must itself be built, deployed, secured, and scaled
- Adds an additional network hop for every API request, from browser to BFF to backend API
- Requires a shared, reliable server-side token store when the BFF runs as more than one instance
- Reintroduces classic cookie-based web security concerns, like CSRF, that a purely token-based SPA architecture doesn’t face in the same way
Hiring a dedicated, trusted courier to handle all your sensitive document transport is a genuine security improvement over carrying the documents yourself through public spaces — but now you also need to trust, pay for, and manage that courier service itself, and make sure its own operations are secure. The BFF pattern trades one set of risks (direct browser exposure) for a different, generally more manageable set (securing a dedicated server-side component).
7Security
CSRF protection is not optional
Because the BFF relies on cookie-based sessions, it inherits cookie-based authentication’s classic vulnerability: cross-site request forgery, where a malicious site tricks a user’s browser into making an unwanted request to the BFF, automatically including their valid session cookie. A BFF implementation must include explicit CSRF protection — typically a synchronizer token pattern or careful use of the SameSite cookie attribute — since this specific risk doesn’t naturally arise in the same way for a purely token-based architecture where a bearer token isn’t automatically attached by the browser to every request.
Context
Teams migrating from a token-based SPA architecture to the BFF pattern sometimes focus entirely on the token-exfiltration benefit while overlooking that the new, cookie-based approach reintroduces a different class of vulnerability that needs its own explicit defense.
Decision
Implement explicit, well-tested CSRF protection as a mandatory, non-optional part of any BFF implementation, using an appropriate combination of SameSite cookie configuration and, for the highest assurance, an explicit CSRF token mechanism for state-changing requests.
Consequence
The security improvement gained by removing tokens from the browser isn’t undermined by trading it for an unaddressed, different vulnerability introduced by the cookie-based session mechanism itself.
Securing the server-side token store
The BFF’s own token store becomes, in effect, a high-value target — anyone able to read from it gains access to real, valid tokens for every active session it holds. This store deserves strong access controls, encryption at rest where appropriate, and the same operational security discipline given to any other system holding sensitive credentials, rather than being treated as an incidental implementation detail.
Storing the BFF’s session-to-token mappings in a shared cache or database with weaker access controls than would be applied to Keycloak’s own credential storage, effectively creating a softer, less-protected copy of exactly the sensitive material the BFF pattern was meant to better protect.
The BFF as a new, security-relevant piece of attack surface
Introducing a new server-side component naturally introduces new attack surface of its own — the BFF’s own code, its dependencies, and its network exposure all deserve the same security scrutiny given to any other internet-facing service, since a vulnerability in the BFF itself (rather than in the frontend or Keycloak) could still provide an attacker a path to the tokens it holds.
8Monitoring, Logging & Metrics
BFF-added request latency
Measuring the additional latency the BFF’s proxying introduces compared to a direct browser-to-API call, ensuring the added hop doesn’t meaningfully degrade the user experience.
Token refresh success/failure rate
Tracking how reliably the BFF’s silent, server-side token refresh mechanism is working, since a failure here directly impacts user session continuity.
CSRF rejection rate
Monitoring how often requests are rejected due to failed CSRF validation, which can reveal either a genuine attack attempt or a frontend implementation bug incorrectly omitting the required protection.
Session store health and consistency
For a horizontally scaled BFF, tracking the health and consistency of the shared token store, since any degradation here directly threatens the reliability of every active user session.
A practical monitoring habit
Teams operating a production BFF often build a dedicated dashboard tracking the added latency the BFF introduces compared to a hypothetical direct API call, alongside token refresh success rate, treating any meaningful degradation in either as an early warning sign worth investigating before it becomes a broader, user-visible reliability problem.
9Design Patterns & Anti-patterns
Proven patterns
One BFF per frontend
Following the pattern’s own name, dedicate a distinct BFF instance to each specific frontend application, tailored to that frontend’s exact needs, rather than building one large, generic BFF shared awkwardly across unrelated frontends.
Shared, distributed session store
Use a proper, shared session/token store (rather than local in-memory storage) from the outset, anticipating the need for horizontal scaling even in an initial, single-instance deployment.
Explicit session-state signaling to the frontend
Build a clear, well-defined way for the BFF to tell the frontend “your session has genuinely ended, please re-authenticate,” distinct from an ordinary, transient request failure.
Defense-in-depth CSRF protection
Combine SameSite cookie configuration with an explicit CSRF token mechanism for state-changing requests, rather than relying on either measure alone.
Anti-patterns to avoid
Anti-pattern
- Building the BFF without genuine CSRF protection, assuming the token-exfiltration benefit alone is sufficient security improvement
- Storing session-to-token mappings only in a single instance’s local memory, breaking the moment the BFF scales beyond one instance
- Leaving the frontend with no clear signal for a genuinely expired session, causing confusing, silent failures
- Treating the BFF’s own token store with weaker security controls than would be applied to Keycloak’s own credential storage
Instead, do this
- Implement explicit, layered CSRF protection as a core, non-negotiable part of the BFF’s design
- Use a shared, distributed session store from the start, anticipating future horizontal scaling needs
- Design a clear, explicit mechanism for signaling genuine session expiry to the frontend
- Apply the same strong access controls and security discipline to the BFF’s token store as to any other sensitive credential storage
10Best Practices & Common Mistakes
Best practices
Design for horizontal scale from the outset
Build the session and token store architecture assuming multiple BFF instances from the beginning, even if initial production load doesn’t yet require it.
Test the full logout and session-expiry paths thoroughly
Verify that logout correctly clears both the BFF’s local state and the underlying Keycloak session, and that genuine session expiry is clearly communicated to the frontend.
Keep the BFF’s own dependency footprint lean and monitored
Since the BFF handles sensitive tokens directly, minimize and carefully monitor its own third-party dependencies for known vulnerabilities.
Load-test the added latency realistically
Confirm the BFF’s added network hop doesn’t introduce unacceptable latency under realistic production traffic patterns, before committing to the architecture at scale.
Common mistakes
Implementing the BFF pattern’s core token-hiding mechanism correctly while overlooking CSRF protection entirely, trading one well-known vulnerability for another, less-considered one.
Building and testing the BFF only against a single instance during development, only discovering session inconsistency problems once deployed with multiple instances behind a load balancer in production.
Underestimating the BFF’s own operational burden — treating it as a trivial proxy that needs no real monitoring, scaling consideration, or security review of its own, despite it now holding every active user’s real tokens.
11Real-world & Industry Examples
Financial technology platforms
Fintech companies, especially sensitive to token theft given the direct financial stakes involved, frequently adopt the BFF pattern specifically to eliminate browser-held tokens as an attack vector for their customer-facing applications.
Healthcare portals
Patient-facing healthcare applications handling protected health information adopt the BFF pattern as part of a broader defense-in-depth strategy, reducing the consequences of any single cross-site scripting vulnerability elsewhere in the frontend.
Enterprise internal tools
Companies building internal, browser-based administrative tools against their own Keycloak deployment use the BFF pattern to simplify frontend token-handling code while gaining the added security benefit for tools with genuinely sensitive administrative capabilities.
Organizations with strict third-party script exposure
Platforms that unavoidably load significant third-party JavaScript — advertising networks, extensive analytics tooling — find the BFF pattern particularly valuable, since it removes tokens as a target regardless of how much untrusted script code the page ultimately runs.
A representative scenario
A fintech company’s single-page application originally stored its Keycloak-issued access and refresh tokens directly in browser memory, following a common but increasingly scrutinized traditional SPA pattern. Following an external security audit that flagged this as a meaningful risk given the application’s extensive use of third-party analytics and customer-support widget scripts, the team re-architected the frontend around a dedicated BFF service. The BFF, registered as a confidential Keycloak client, now handles the entire OAuth flow and token lifecycle server-side, while the browser holds only a well-protected, HttpOnly session cookie — eliminating the exact token-exfiltration risk the audit had identified, without requiring the frontend’s actual user experience or feature set to change in any noticeable way.
12FAQ
13Summary and Key Takeaways
Key Takeaways
- The Backend-for-Frontend (BFF) pattern introduces a dedicated server-side component that performs the OAuth flow with Keycloak and holds tokens entirely server-side, keeping them out of the browser’s JavaScript-accessible context.
- The browser interacts only through an HttpOnly session cookie, never receiving the actual access or refresh token directly.
- The BFF is registered in Keycloak as a confidential client, using the standard Authorization Code flow, but relocated entirely to the server side rather than the browser.
- This architecture directly closes off token exfiltration through cross-site scripting, a significant and historically common risk for traditional, browser-held-token SPA architectures.
- It reintroduces cookie-based session risks, particularly CSRF, which must be explicitly and deliberately defended against as a core part of the implementation.
- A production-grade BFF requires a shared, distributed session/token store to support horizontal scaling reliably across multiple instances.
- The pattern trades additional infrastructure and complexity for a meaningfully stronger security posture, a trade increasingly favored by current OAuth security best practices.
- Real-world adoption concentrates in fintech, healthcare, and enterprise applications — anywhere token security is a genuine priority and the added architectural investment is justified.