Proxy & CORS
This page explains why pattern B (a same-origin GraphQL proxy) avoids CORS
for the widget, and when pattern A (direct GraphQL + getHeaders) requires
CORS to be configured. See Authentication for the full
integration guidance.
The widget itself has no auth logic.
CORS is a browser rule
CORS limits JavaScript on one origin from reading responses from another origin unless the remote server explicitly allows it. It does not apply to server-to-server HTTP.
Pattern A — Direct GraphQL (CORS required)
| Page | https://customer-portal.example.com |
Widget apiUrl | https://api.kraken.example.com/graphql |
The widget runs fetch() in the browser toward the API. That is
cross-origin, so the API (or your gateway) must respond with CORS headers
(Access-Control-Allow-Origin, Access-Control-Allow-Methods,
Access-Control-Allow-Headers) for your site's origin, or the browser blocks
the response.
You also supply auth via getHeaders (e.g. Authorization: Bearer …).
Pattern B — Same-origin proxy (no CORS for the widget)
| Page | https://customer-portal.example.com |
Widget apiUrl | https://customer-portal.example.com/api/graphql |
The widget only talks to your app — same protocol, host, and port → same origin → no cross-origin restriction on that request.
Your server then calls the upstream API:
Your server → https://api.kraken.example.com/graphql
That hop is server-to-server, so CORS does not apply. Your proxy attaches
Authorization (from the session, cookies, or a server-side token store) before
calling upstream.
Takeaway: with a proxy, the widget never crosses origins to reach the API. Only your server does.
End-to-end flow (pattern B)
┌─────────────┐ POST /api/graphql ┌──────────────┐ POST + Authorization ┌────────┐
│ Widget │ ─────────────────────────► │ Your proxy │ ────────────────────────► │ Kraken │
│ (browser) │ cookies (optional) │ (your app) │ Bearer from server │ GraphQL│
└─────────────┘ no Authorization header └──────────────┘ └────────┘
The widget does not add Authorization. Your proxy reads the session
server-side and builds a new authenticated request to the upstream API.
Summary
| Question | Pattern A (direct) | Pattern B (proxy) |
|---|---|---|
| Browser CORS needed? | Yes | No (same origin) |
Who adds Authorization? | getHeaders in widget config | Your proxy route |
| Where is the token? | Client (your app manages) | Server / httpOnly cookies (your app manages) |
Related
- Authentication — patterns A vs B, checklists.
- Next.js & blueprint-auth — a concrete pattern B setup for Next.js.