54321G
Liftira
HomeArticleAboutContactDocs

Getting started

Exchanging a session token

The two-step exchange that turns your license key into a session token the browser can safely use — and why it happens in two hops, not one.

Also available in Vietnamese

Your license key must live on your server only — it should never reach the browser. Getting a working session token takes two separate requests, not one: your server requests a short-lived exchange code, then the browser itself trades that code for the real session token. Splitting it this way lets Comnoira independently confirm the request is really coming from your website before it hands out anything usable.

Step 1 — your server requests an exchange code

curl -X POST https://api.comnoira.com/viewer/session \
  -H "X-License-Key: $COMNOIRA_LICENSE_KEY" \
  -H "Content-Type: application/json"

The response is not a usable session token — it's an opaque, single-use exchange code:

{
  "exchangeToken": "exch_9f2c...",
  "expiresAt": "2026-08-06T12:01:00Z"
}

This code expires in 60 seconds and can only be exchanged once. Request it fresh on every page load — don't cache it, and don't retry with one that's already been exchanged.

Step 2 — hand it to the browser, let the SDK finish the exchange

Return exchangeToken from your own backend route. The embed script's getSessionToken callback should return this value — despite the name, at this point it's returning the exchange code, not the final session token:

<div id="comnoira-viewer"></div>
<script src="https://cdn.comnoira.com/sdk/v1/comnoira.min.js"></script>
<script>
  function getSessionToken() {
    return fetch('/your-backend-route')
      .then((res) => res.json())
      .then((data) => data.exchangeToken);
  }

  Comnoira.init({
    target: '#comnoira-viewer',
    model: 'your-model-id',
    getSessionToken,
  });
</script>

From there, the SDK calls Comnoira directly from the buyer's browser to complete the exchange — this is the step that actually produces a usable session token:

POST https://api.comnoira.com/viewer/session/exchange
{ "exchangeToken": "exch_9f2c..." }

Comnoira checks the browser's real Origin header against the domains registered to your embed and confirms your license is still active — only if both pass does it mint a session token and hand it back to the browser. The SDK then uses that token to boot the viewer iframe.

If the embed fails silently with no console error, the most common cause is an origin mismatch — the page's domain isn't registered to the embed code you're using. Check that first, against your Comnoira dashboard, before anything else.

Why two hops instead of one

Handing your server's response straight to the browser would mean trusting whatever domain your server says it's serving — easy to get wrong across redirects, staging domains, and preview deployments. Making the browser complete the exchange itself means Comnoira checks the domain the request is actually coming from, not just what your server claims. It also means the exchange code and the session token it produces can expire and be revoked independently of each other.

If the viewer mounts but shows a blank frame, it's almost always a session token that's expired or already consumed — request a fresh exchange code and reload.