How do I authenticate the embed with JWT?

Sign a JWT to secure your embed and keep it loading in Safari and privacy-blocking browsers.

Updated

Orshot Embed typically relies on Referrer Headers to ensure that your embed is only loaded on allowed domains. However, some browsers (like Safari) or privacy extensions may strip these headers, causing the embed to fail validation.

To solve this, Orshot supports JWT (JSON Web Token) authentication. By signing a token on your server and passing it to the embed, you can securely authorize access without relying on browser headers.

When to use this?#

  • If you have users on Safari facing "Access Denied" errors.
  • If you are embedding inside an invalid environment (e.g. some mobile webviews).
  • If you want an extra layer of security beyond domain whitelisting.

Setup#

1. Generate Signing Secret#

Open Orshot Embed, expand Authentication (JWT), and click the refresh button next to Signing Secret to generate one.

2. Sign a Token (Server-Side)#

On your backend, sign a JWT with this secret. Any payload works. Optional sub and permissions claims identify the user and lock actions (see below).

Example (Node.js):

JavaScript
import jwt from "jsonwebtoken";

const SIGNING_SECRET = "your-signing-secret-from-dashboard";

// Generate a token (valid for 1 hour)
const token = jwt.sign(
  {
    embedId: "your-embed-id", // Optional context
    nonce: Math.random(), // Prevent replay attacks (optional)
  },
  SIGNING_SECRET,
  { expiresIn: "1h" }, // Short expiry recommended
);

const embedUrl = `https://orshot.com/embeds/YOUR_EMBED_ID?token=${token}`;

3. Pass Token to Embed#

Append the token query parameter to your embed URL.

HTML
<iframe
  src="https://orshot.com/embeds/12345?token=YOUR_GENERATED_TOKEN"
  title="Orshot Embed"
  width="100%"
  height="600"
  style="border: none;"
  allow="clipboard-write"
></iframe>

Identify the User and Lock Actions#

Add either optional claim to the payload:

ClaimWhat it does
subYour user's id, used in place of ?userId=. Only read when Require signed token is on. Follows the userId rules: up to 256 letters, numbers, _, -, @ or . (numbers work too)
permissionsActions to lock for this session, for example { "template/delete": true }
JavaScript
const token = jwt.sign(
  {
    sub: "user_123",
    permissions: { "template/delete": true },
  },
  SIGNING_SECRET,
  { expiresIn: "15m" },
);

See User Permissions for every permission key and how token locks combine with the ones saved in the dashboard.

Require Signed Token#

Turn on Require signed token under Authentication (JWT) and click Save Settings. The embed then:

  • Refuses to load without a valid token, and the token must have an expiry (exp)
  • Takes the user from the token's sub and ignores ?userId=
  • Refuses an invalid sub, and a missing one when per-user data is on

The Preview in your dashboard keeps working.

Turn it on only once every page that loads the embed passes a token. Loads without one are refused.

Fallback Behavior#

With Require signed token off, an invalid or expired token falls back to the allowed-domains check, so users on an allowed domain still get in. With it on, there is no fallback: the embed shows Access Denied instead.

Security Best Practices#

  • Short Expiry: Set a short expiration time (e.g., 1h or even 5m) for your tokens. The token is only needed for the initial load.
  • Backend Only: NEVER expose your Signing Secret on the client-side. Always generate the token on your server.
Was this page helpful?

Ready to automate?

Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.

Get your API key
  • Image, PDF and video generation via API
  • Visual editor with AI and smart layouts
  • Zapier, Make, MCP and 40+ integrations
  • White-label embed for your own app
  • 100 free credits a month, no credit card required