Getting Started

/

Session Tokens

Session Tokens

A session token is a short-lived JWT minted by your backend that authorizes a single browser session to mount and operate a Moshpit embed.

Token format

Sessions are HS256-signed JWTs with this payload shape:

TS

TypeScript

{
  typ: 'moshpit_embed_session';
  sub: string; // owner ID
  identityUserId: string;
  integrationId: string;
  publicKey: string; // mpk_...
  capabilities: Array<'editor' | 'viewer'>;
  iat: number; // issued at
  exp: number; // iat + 900 (15 minutes)
}

You don't need to verify this yourself — Moshpit verifies it on every iframe load and every API call. The shape is documented for transparency.

Lifetime

Every session expires 15 minutes (900 seconds) after it is minted. Generating an integration secret in Studio does not start the timer — the timer starts when the host backend actually requests a session.

If the browser keeps the embed open longer than 15 minutes, the iframe needs a new token before the old one expires. The SDK handles this for you; for plain iframes you have to do it yourself.

Mint a session

Always mint sessions from your backend. Pass the secret as a Bearer token:

SH

Bash

curl -X POST https://moshpit.studio/api/editor/embed-sessions \
  -H "Authorization: Bearer msk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "publicKey": "mpk_YOUR_PUBLIC_KEY",
    "type": "viewer",
    "splatId": "65f1a2b3c4d5e6f7a8b9c0d1"
  }'

The response:

{}

JSON

{
  "status": "success",
  "sessionToken": "eyJhbGciOiJIUzI1NiI...",
  "expiresAt": "2026-05-08T13:30:00.000Z"
}

See POST embed-sessions for the full request/response reference.

Plan access

All plans can mint Viewer and Editor Embed sessions and use the REST API. Session mints and REST calls are not metered. Storage, Scene counts, and integration limits still apply. Enterprise supports pay-as-you-go overage.

Refresh before expiry

When the SDK is in use, it fires a sessionExpiring event roughly 60 seconds before the JWT expires. You don't need to handle this manually — if you provided a sessionEndpoint or getSessionToken callback, the SDK calls it and applies the new token.

For plain iframes the responsibility shifts to your code:

JS

JavaScript

async function refreshMoshpitSession(iframe, splatId) {
  const res = await fetch('/api/moshpit/viewer-session', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ splatId }),
  });
  const { sessionToken, expiresAt } = await res.json();
 
  iframe.contentWindow.postMessage(
    {
      source: 'moshpit-sdk',
      type: 'command',
      target: 'viewer', // or 'editor'
      command: 'updateSession',
      value: { sessionToken, expiresAt },
    },
    'https://moshpit.studio',
  );
 
  // Schedule the next refresh ~60s before the new expiry
  const ms = new Date(expiresAt).getTime() - Date.now() - 60_000;
  setTimeout(() => refreshMoshpitSession(iframe, splatId), Math.max(ms, 5_000));
}

Refresh failures stop the embed

If a refresh request fails and the current token expires before the next retry, the iframe stops accepting API calls. Always reload the iframe from scratch as a fallback when refresh fails repeatedly.

Why 15 minutes?

The short lifetime is intentional. A leaked token has a small blast radius: an attacker who steals one can act for up to 15 minutes, not indefinitely. Increase the safety margin further by:

  • Restricting your session endpoint to authenticated users on your platform.
  • Enforcing rate limits on your session endpoint.
  • Rotating the integration secret periodically.

What's next