Skip to content

Content Security Policy (CSP)

TokenFlight widgets inject styles into Shadow DOM. If your page has a strict Content Security Policy, you need to allow these styles.

Should you read this?

Read this page if your app sets a CSP header, uses nonce-based styles, or runs in a locked-down checkout environment.

If your app does not use CSP yet, you can ship the widget first and return before production hardening.

What the widget needs

  • style-src must allow the widget's Shadow DOM styles.
  • style-src-attr must allow inline style attributes — see Nonces and style attributes.
  • connect-src must allow your configured API endpoint.
  • Card checkout also needs connect-src for the configured fiat API endpoint.
  • connect-src must also allow https://embed.tokenflight.ai — the widget reads a shared defaults document from there on every boot, regardless of your api-endpoint.
  • img-src must allow chain icons and token logos.

The csp-nonce Attribute

Pass a nonce to the widget, and it will include it on all injected <style> elements:

html
<tokenflight-widget csp-nonce="abc123" theme="dark" to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100"></tokenflight-widget>

Or create the custom element from JavaScript and set the same HTML attribute before appending it:

js
// The csp-nonce is an HTML attribute on the custom element
const el = document.createElement('tokenflight-widget');
el.setAttribute('csp-nonce', 'abc123');
el.setAttribute('theme', 'dark');
el.setAttribute('to-token', 'eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913');
el.setAttribute('trade-type', 'EXACT_OUTPUT');
el.setAttribute('amount', '100');
document.getElementById('container').appendChild(el);

The csp-nonce attribute applies to the custom element path. If you use the TokenFlightWidget JavaScript class in a nonce-only CSP environment, test styles carefully or use the custom element path for strict nonce support.

Nonces and style attributes

A nonce covers the <style> elements the widget injects — that is the style-src-elem half of the policy, and it is what csp-nonce is for.

The widget also renders inline style attributes on some elements. A nonce cannot authorize a style attribute — the CSP spec has no mechanism for it — so a nonce-only policy blocks them and logs style-src-attr violations. Allow them explicitly:

http
style-src 'self' 'nonce-abc123';
style-src-attr 'unsafe-inline';

This is deliberately narrower than putting 'unsafe-inline' on style-src itself: injected stylesheets stay nonce-gated, and only the attributes are relaxed. If you omit style-src-attr entirely it inherits from style-src, which is what produces the violations.

Required CSP Directives

http
Content-Security-Policy:
  style-src 'nonce-{your-nonce}';
  style-src-attr 'unsafe-inline';
  connect-src https://your-api-endpoint.example.com https://fiat.hyperstream.dev https://embed.tokenflight.ai;
  img-src https://your-api-endpoint.example.com https: data:;
DirectiveValuePurpose
style-src'nonce-{value}'Injected Shadow DOM stylesheets
style-src-attr'unsafe-inline'Inline style attributes the widget renders — a nonce cannot cover these
connect-srchttps://your-api-endpoint.example.com, https://embed.tokenflight.ai, and https://fiat.hyperstream.dev if card checkout is enabledAPI requests (quotes, orders, tokens, fiat checkout) and the shared defaults document
img-srchttps://your-api-endpoint.example.com plus token logo domains, and the embed config origin for transfer QR imagesChain icons (/v1/chain/{id}/icon), token logos, and transfer-rail QR codes

Replace your-api-endpoint.example.com with the domain of your configured apiEndpoint. https://embed.tokenflight.ai is a fixed TokenFlight origin and is not derived from api-endpoint — see below.

Why embed.tokenflight.ai is in connect-src

On boot the widget fetches https://embed.tokenflight.ai/api/config/defaults.json, a shared document that lets TokenFlight ship default configuration without a version bump. Blocking it is not fatal — the widget falls back to its built-in defaults — but it retries three times and logs a CSP violation each time, so leaving it out means a console full of errors on every page load.

If you load the widget bundle from embed-staging.tokenflight.ai, that origin is used instead; allow whichever one you serve from.

When the manual-transfer (ODA) rail is enabled, transfer QR codes are served as images from the embed config origin's /api/qrcode endpoint (or your qr-code-api-url override). Make sure img-src allows that origin — the https: data: values in the example below already cover same-origin and inline data: images.

Full CSP Header Example

http
Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'nonce-abc123';
  style-src-attr 'unsafe-inline';
  connect-src 'self' https://your-api-endpoint.example.com https://fiat.hyperstream.dev https://embed.tokenflight.ai;
  img-src 'self' https://your-api-endpoint.example.com https: data:;
  font-src 'self';

Verify by loading a page under this exact policy and confirming the browser console reports zero CSP violations. A widget that renders is not proof — blocked styles and a blocked defaults fetch both degrade quietly.

INFO

Token icon images (logoURI) may come from various CDNs. If you see broken token icons, check your img-src directive and add the necessary domains. Chain icons use the API endpoint path /v1/chain/{id}/icon.

Without a Nonce

If you cannot use nonces (e.g., static hosting without server-side header injection), you can use 'unsafe-inline' for style-src:

http
style-src 'self' 'unsafe-inline';

This is less secure but allows the widget's Shadow DOM styles to load without a nonce. It also covers the inline style attributes, so no separate style-src-attr entry is needed in this form.

Next step