
The BFF Pattern: Wiring Next.js to FastAPI Securely
After splitting the frontend and backend, the first question is: how will the browser reach the API? The easiest route is keeping the JWT in localStorage. But that means an XSS hole leaks the token. Instead I chose the BFF (Backend-for-Frontend) pattern.
The core idea
The browser never sees the backend. All sensitive communication happens on the Next.js server side:
- On login, FastAPI returns a JWT.
- Next.js stores that token in an httpOnly, encrypted
iron-sessioncookie. JavaScript can't touch it. - Later admin requests read the token from the cookie on the server (Server Action / RSC) and call the API with a
Bearerheader.
The flow
browser → Next login action → FastAPI /auth/login → JWT
JWT → httpOnly iron-session cookie (stored in browser, unreadable)
later request → Server Action getToken() → FastAPI with Bearer
So the token lives in the browser, but inside a vault JavaScript can't open. Even with XSS, the token doesn't leak.
Cookie security: a small but critical detail
During development I noticed the session dropped on every refresh. The cause: a secure cookie is only sent over HTTPS; over plain HTTP on the LAN the browser was discarding it.
secure: process.env.COOKIE_SECURE === "true"
In production (Traefik HTTPS)COOKIE_SECURE=true, in local plain-HTTP testingfalse. The right value for the right environment.
Why it's worth it
The BFF pattern means a bit more server code, but in return the token never touches browser JavaScript, the API is never directly exposed to the internet, and /api/* is proxied only for images. To me that's the healthiest balance between security and developer experience.