Skip to content

CORS — allowed origins

When the user's browser is running your SPA at https://app.cymmetri.com and the SPA fetches /api/v1/me/profile on the tenant URL, the browser sends a CORS preflight to ask the tenant "is https://app.cymmetri.com allowed to talk to you?"

The platform answers yes if your application has https://app.cymmetri.com on its Allowed origins list. No, otherwise. The browser refuses to expose the response to your code on a no.

You'll set this once per environment, and probably forget about it until you change a host.

Application detail → Settings tab → Redirect URIs section → Allowed origins. One origin per line.

An origin is scheme://host[:port]. Note: no path. /callback belongs in redirect URIs, not here.

Valid examples:

https://app.cymmetri.com
https://staging.cymmetri.com
http://localhost:5173

Invalid (rejected on save):

https://app.cymmetri.com/ ← trailing slash
https://app.cymmetri.com/callback ← path included
https://*.cymmetri.com ← wildcard
* ← any-origin

The browser's Origin header on the request is matched character-for-character (after URL normalisation) against the registered list. Match → CORS headers come back saying "this origin is allowed". No match → no CORS headers, browser refuses.

Important: the platform does NOT echo Origin: * even if a registered origin matches. It echoes the specific origin. This is required when your app uses credentials: 'include' for cookie-bearing fetches (the browser refuses to send credentials to a * CORS response).

For a typical SPA, register every origin your code might fetch from:

  • Productionhttps://app.cymmetri.com
  • Staginghttps://staging.cymmetri.com
  • Local devhttp://localhost:5173 (Vite default), http://localhost:3000 (Next.js default), or whatever your dev server runs on.

If your team uses preview deployments (Vercel preview, Netlify preview), each unique preview URL would need to be on the list — which is impractical. The pragma there is either:

  • Don't make IntelliAuth calls in preview environments; only test against staging / production.
  • Use a per-developer staging tenant with its preview URLs registered.

Wildcards aren't supported (see below), so there's no shortcut for dynamic preview URLs.

The platform refuses wildcard origins. https://*.cymmetri.com is rejected on save. The reason: a single misregistered origin lets any subdomain of yours request tokens, which fans out blast radius if any subdomain is compromised.

If you genuinely have many subdomains and they all need access, register each one. If that's hundreds, your architecture is doing something unusual; consider whether you really want IntelliAuth calls from every subdomain or whether a single gateway origin would be cleaner.

These two lists overlap but aren't the same:

What it's forFormat
Allowed originsBrowser fetch CORSscheme://host[:port] (no path)
Redirect URIsWhere the browser lands after sign-inscheme://host[:port]/path (path required for HTTP URIs)

Both lists need maintaining; they're independent. A common mistake: registering https://app.cymmetri.com/callback in allowed origins (it's a redirect URI, not an origin) or https://app.cymmetri.com in redirect URIs (it has no path).

The browser console reports something like:

Access to fetch at 'https://banking-cymmetri.intelliauth.local/api/v1/me/profile' from origin 'https://app.cymmetri.com' has been blocked by CORS policy

Walk these checks:

  1. What origin is in the error? Copy it from the console message.
  2. Is that origin in Allowed origins? Application detail → Settings tab → Allowed origins. Look for exact match.
  3. Did the browser cache an old preflight? The browser caches CORS preflights for up to an hour. After adding the origin, hard-reload (Cmd-Shift-R) or wait it out.
  4. Is the underlying request actually OK? Sometimes a 401 or 500 manifests as "CORS error" because the failed response doesn't carry CORS headers. Check the response status in the network tab.

The CORS errors developer troubleshooting topic walks the same diagnostic from the developer's side.