Skip to main content

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.

note

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:

PatternapiUrlgetHeadersBrowser CORSWho owns login & token refresh?
A. DirectKraken (or any) GraphQL URLRequired — e.g. AuthorizationYes — cross-origin from your pageYour app (client-side)
B. Proxy / BFFSame-origin route on your app (e.g. /api/graphql)OmitNo — widget only calls your originYour 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 POST handler 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 tokenTokens live in httpOnly cookies or server-only storage
You already call the API from the browser elsewhereYou want to avoid exposing the upstream URL or tokens to JS
CORS is already configuredYou centralise token refresh on the server

Integrator checklist

  • The GraphQL API exposes the Ink operations your widget version expects.
  • Pattern A: CORS is configured, getHeaders returns the current Authorization, and your app refreshes tokens.
  • Pattern B: the proxy route authenticates and forwards; the widget apiUrl is the proxy URL; getHeaders is omitted.
  • accountNumber and userEmail are set for the signed-in user's context.
  • The widget is not mounted for unauthenticated users (when auth is required).