Backend for Frontend (BFF)
A Backend for Frontend, or BFF, protects a browser app by keeping OAuth tokens away from browser JavaScript.
With an AuthGate BFF gateway, users open your app through the gateway URL:
https://your-store.authgate.siteAuthGate can serve your registered frontend app, handle login under /bff/*, and forward API calls to your backend services.
Why BFF exists
Many beginner apps store access tokens in localStorage. That is easy, but risky.
If harmful JavaScript runs on the page, it can read localStorage. If the access token is there, the attacker can copy it.
A BFF avoids that pattern:
- the browser does not receive the access token
- AuthGate stores the BFF session server-side
- the browser only receives an
HttpOnlycookie - JavaScript cannot read an
HttpOnlycookie
Frontend app
In a BFF gateway, the frontend app is the deployed browser app that AuthGate should serve.
Example:
| Thing | Example |
|---|---|
| Frontend app origin | https://mori-market.vercel.app |
| Gateway entrypoint | https://mori-market.authgate.site |
Users should open the gateway entrypoint, not the original frontend origin.
That keeps pages, session endpoints, and API routes on the same site.
BFF session endpoints
AuthGate reserves these paths for the BFF flow:
| Endpoint | Meaning |
|---|---|
GET /bff/login | Starts OAuth2 login with the IAM client bound to the gateway. |
GET /bff/callback | Receives the OAuth2 authorization code and creates the BFF session. |
GET /bff/me | Checks whether the browser has a valid BFF session. |
POST /bff/logout | Deletes the BFF session and clears the cookie. |
Your frontend can check the session like this:
const response = await fetch('/bff/me', {
credentials: 'include'
})HttpOnly session
After login, AuthGate creates a cookie named:
AUTHGATE_BFF_SESSIONImportant details:
- it is
HttpOnly, so frontend JavaScript cannot read it - it uses
SameSite=Lax - secure routes validate this session before forwarding the request
- AuthGate strips the BFF session cookie before forwarding to your upstream service
Do not write browser code that tries to read the BFF cookie. That is the point of HttpOnly: the browser sends it automatically, but JavaScript cannot access it.
Public and secure routes
BFF gateways support both guest and logged-in behavior.
| Route type | Example | Login required? |
|---|---|---|
| PUBLIC | GET /api/products | No |
| PUBLIC | GET /api/products/{id} | No |
| SECURE | POST /api/products/add | Yes |
| SECURE | PATCH /api/products/{id} | Yes |
This is useful for normal ecommerce behavior:
- visitors can view products before login
- logged-in users can open account pages or perform protected actions
Why /api/... is recommended
/api/... is not magic. It is a convention that prevents route conflicts.
For example:
| Path | Should be |
|---|---|
/products | frontend page |
/products/1 | frontend page |
/api/products | backend API route |
/api/products/1 | backend API route |
If a gateway route and a frontend page use the same path, the gateway route wins. That can make a page show JSON instead of the real website.
BFF setup checklist
Before testing a BFF app, confirm these five items:
- IAM OAuth2 client exists.
- BFF gateway is bound to that OAuth2 client.
- OAuth2 client contains the gateway callback URL, for example
https://your-store.authgate.site/bff/callback. - Frontend app origin is registered in the Frontend Apps tab.
- Backend service routes exist for both public reads and secure actions.
What the frontend code should do
For login:
window.location.href = '/bff/login?return_to=/'For public data:
await fetch('/api/products', {
credentials: 'include'
})For secure data:
await fetch('/api/profile', {
credentials: 'include'
})The frontend should not store access tokens in localStorage, sessionStorage, or regular readable cookies.
Current gateway behavior
For SECURE BFF routes, AuthGate validates the BFF session at the gateway before forwarding the request to the upstream service.
This means your browser app proves login by sending the BFF session cookie, not by sending an Authorization: Bearer ... header.