Skip to main content
ABScaleForge
Back to blog
2 min read

Next.js BFF Pattern — Fixing Cross-Domain Laravel API Calls

Why we built Billings as a Next.js backend-for-frontend that proxies to Laravel — eliminating CORS, CSRF, and broken session cookies in the browser.

Next.jsLaravelSanctumBFFReact Query

Browsers struggle to call Laravel APIs on another domain. CORS preflights fail, cookies do not cross origins cleanly, and CSRF tokens break SPA login flows. We hit this building the Prime Alley billing suite.

The problem with direct browser → Laravel

When the React app talks directly to api.example.com from app.example.com:

  • Session cookies need careful SameSite and domain configuration
  • CSRF tokens must be fetched and attached on every mutating request
  • Token refresh and redirect-on-expiry logic duplicates across every client
  • Mobile and third-party clients inherit the same fragility

The BFF solution

Billings uses the backend-for-frontend pattern:

1. The browser only talks to Next.js on the same origin 2. Next.js server routes proxy to Laravel with server-side credentials 3. Expired sessions redirect to login — no half-authenticated states 4. React Query handles client caching against the BFF, not Laravel directly

The user gets a fast SPA experience. Laravel stays the source of truth for invoices, companies, customers, payments, roles, and audit logs.

What we kept on Laravel

Accounts remains the central auth and billing API — login, Stripe, companies, vendors, invoices. Billings is the modern UI layer. GSM handles Stripe checkout separately for a lighter payment flow.

When to use this pattern

Use a BFF when:

  • Your API predates your frontend and rewriting it is expensive
  • You need cookie-based auth without exposing Laravel to the public internet
  • You want one deployment surface for the browser while keeping microservices behind it

Do not use a BFF when a single Next.js full-stack app with its own database is simpler — match the pattern to the constraint.