Skip to main content

CORS & allowed origins

Publishable keys (kld_pk_live_…) carry an allowed-origins list — the browser origins permitted to use the key. Set it when you mint the key (e.g. https://acme.com, https://app.acme.com); a live publishable key requires at least one. Server keys (kld_sk_live_…) get no CORS grant, so a page can never read a response made with one. Note what that does and doesn't cover: CORS blocks the response, not the request — a server key embedded in page source has already been exposed regardless. The SDK therefore refuses kld_sk_… at mount; server keys are server-to-server only.

How it's enforced

  • Preflight (OPTIONS) is permissive — it reflects the requested origin so the browser proceeds (the key isn't presented on a preflight).
  • The real request only gets an Access-Control-Allow-Origin header back when the request Origin is in the key's allowed list. A non-allowlisted origin gets no ACAO header, so the browser blocks the response.

No cookies are involved — the platform API is bearer-token auth, so there is no Access-Control-Allow-Credentials.

Publishable keys travel in URLs to the tile CDN

tile.kaleidr.com takes your publishable key as a ?key= query parameter. That is by design, and it has a consequence worth stating plainly: query strings are recorded in CDN access logs, browser history, and any proxy in between.

This is acceptable because a publishable key is public by construction — it already ships in your page source. The control that makes it safe is the per-key origin allowlist, which the edge enforces on every tile request, plus the key being restricted to the maps scope.

It is not acceptable for a server key. Never put kld_sk_… in a URL, and note that a leaked server key is already exposed by the time the API refuses it.

Everywhere else — the SDK session exchange, the platform API — the key travels as a header, never a query parameter.

Tips

  • Use bare origins (scheme://host[:port]) — no path, no trailing slash — so they match the browser's Origin header exactly.
  • https is required except for localhost / 127.0.0.1 (local testing).
  • Server-to-server calls with a server key (no browser Origin) aren't CORS-gated, but still authenticate + scope-check normally.