Authentication
The widget does not log in, read cookies, store credentials, refresh tokens,
or attach bearer tokens by itself. Your application authenticates GraphQL
requests and exposes an endpoint the widget can POST to from the browser.
Before every GraphQL request, the widget calls the optional getHeaders()
callback (default: none). Whatever headers you return are sent with the request.
That is the only auth hook built into the widget.
accountNumber and userEmail are session config (message identity), not
credentials. They do not replace authentication.
Two integration patterns
Every integration is one of these two shapes:
| Pattern | apiUrl | getHeaders | Browser CORS | Who owns login & token refresh? |
|---|---|---|---|---|
| A. Direct | Kraken (or any) GraphQL URL | Required — e.g. Authorization | Yes — cross-origin from your page | Your app (client-side) |
| B. Proxy / BFF | Same-origin route on your app (e.g. /api/graphql) | Omit | No — widget only calls your origin | Your server |
The widget behaves identically in both cases — only apiUrl and getHeaders
change. Pick the pattern that matches how your app stores and forwards
credentials.
Pattern A — Direct GraphQL (getHeaders)
Use when the browser can access a valid access token (in memory, via your auth SDK, etc.) and you want the widget to call the GraphQL API directly.
el.setConfig({
apiUrl: 'https://api.example.com/graphql',
accountNumber,
userEmail,
getHeaders: async () => ({
Authorization: `Bearer ${await getAccessToken()}`,
}),
});
getHeaders runs before every GraphQL request (send, poll, close). Return a
fresh token when your app has refreshed it.
Your responsibilities:
- Obtain the access token after login.
- Refresh or replace expired tokens before the next widget request (the widget does not refresh).
- Configure CORS on the GraphQL endpoint for your site's origin — see Proxy and CORS.
Typical stacks: SPAs (Vite, Vue, CRA), mobile web views where client code
holds the token, or any app already calling the API from the browser with
Authorization.
Pattern B — Same-origin proxy / BFF
Use when tokens must stay off the client (httpOnly cookies, server-side session) or you want to hide the upstream GraphQL URL from the browser.
Widget (browser)
→ POST https://your-app.example.com/api/graphql
(no Authorization header from widget; cookies may be sent automatically)
Your proxy route (server)
→ read session / token from cookie or server store
→ attach Authorization: Bearer …
→ forward to Kraken GraphQL
→ return JSON to the widget
Widget config:
import { init } from '@krakentech/ink-live-chat-widget';
init(document.getElementById('chat-root'), {
apiUrl: 'https://your-app.example.com/api/graphql',
accountNumber: 'A-B280147D',
userEmail: 'user@example.com',
// omit getHeaders — your server attaches the bearer token
});
Use an absolute URL for apiUrl (the widget validates it with new URL()).
Your responsibilities:
- User login and session storage (your auth stack).
- A
POSThandler that authenticates the caller and forwards GraphQL upstream. - Token refresh on the server before upstream requests fail.
- Protecting pages that render the widget so unauthenticated users never mount it.
Typical stacks: Next.js, Express, Laravel, or any backend that can expose a GraphQL forwarder on the same origin as the page.
Illustrative proxy route
Framework-agnostic sketch — adapt to your stack. Requires an authenticated session.
// POST /api/graphql — illustrative only
export async function POST(request: Request) {
const session = await getSessionFromYourAuth(request);
if (!session?.accessToken) {
return Response.json(
{ errors: [{ message: 'Not authenticated' }] },
{ status: 401 },
);
}
const body = await request.json();
const upstream = await fetch(process.env.KRAKEN_GRAPHQL_ENDPOINT!, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${session.accessToken}`,
},
body: JSON.stringify(body),
});
return new Response(await upstream.text(), {
status: upstream.status,
headers: { 'Content-Type': 'application/json' },
});
}
Choosing between A and B
Prefer A (direct + getHeaders) when… | Prefer B (proxy) when… |
|---|---|
| The client already has the token | Tokens live in httpOnly cookies or server-only storage |
| You already call the API from the browser elsewhere | You want to avoid exposing the upstream URL or tokens to JS |
| CORS is already configured | You centralise token refresh on the server |
Integrator checklist
- The GraphQL API exposes the Ink operations your widget version expects.
- Pattern A: CORS is configured,
getHeadersreturns the currentAuthorization, and your app refreshes tokens. - Pattern B: the proxy route authenticates and forwards; the widget
apiUrlis the proxy URL;getHeadersis omitted. -
accountNumberanduserEmailare set for the signed-in user's context. - The widget is not mounted for unauthenticated users (when auth is required).
Related
- Proxy and CORS — why pattern B avoids browser CORS.
- Next.js & blueprint-auth — an optional reference implementation of pattern B.
- Configuration reference —
getHeaders,apiUrl, and required fields.