Docs

Private videos

Restrict a video to authenticated viewers with short-lived access tokens.

By default every video is public: anyone who can reach the embed or the playback API can watch it (subject to your origin and app rules). A private video plays nothing and serves none of its assets unless the request carries a valid access token that your backend signs.

1. Enable token access and create a signing key

In the dashboard, open Settings → Video:

  1. Turn on token access for the organization.
  2. Create a signing key. The secret (prefixed mvi_sign_) is shown once: store it securely in your backend. It never expires; you can rotate or revoke it at any time.

Keep the signing key on your server. Never expose it to browsers or ship it in a client app.

2. Mark a video as private

On the video's Security tab, switch Visibility to Private. You can also set a per-organization default visibility so new videos start private automatically: changing the default only affects videos created afterward.

3. Mint an access token

When a viewer should be allowed to watch, your backend signs a short-lived JWT (algorithm HS256) with the signing key secret:

Header

{ "alg": "HS256", "kid": "<signing-key-id>" }

Claims

{
  "sub": "<video-id>",   // REQUIRED: the video this token authorizes
  "exp": 1717070400,      // REQUIRED: expiration (epoch seconds); keep it short
  "iat": 1717070100       // REQUIRED: issued-at
}
  • exp is mandatory: a token without it is rejected.
  • sub binds the token to one video. A token presented for any other video is rejected.
  • Mint a fresh token per playback session and keep exp short (minutes).
import jwt from "jsonwebtoken"

const token = jwt.sign({ sub: videoId }, signingKeySecret, {
  algorithm: "HS256",
  keyid: signingKeyId,
  expiresIn: "5m",
})

4. Present the token

Embedded player: pass it as the token query parameter:

<iframe
  src="https://watch.moviie.ai/embed/EMBED_ID?token=THE_JWT"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen
></iframe>

Playback API: send it in the x-moviie-playback-token header, alongside the publishable key you already use:

GET /api/v1/embeds/EMBED_ID/playback
Authorization: Bearer <publishable-key>
x-moviie-playback-token: THE_JWT

Outcomes

SituationResult
Valid tokenPlays; assets returned as short-lived signed URLs
Missing / invalid / expired token401 (player shows a blocked message)
Token for a different video403
Token signed by a revoked key401

Asset URLs returned for a private video are short-lived: request them again through the same endpoint instead of caching them.

Rotating and revoking

  • Rotate: create a new signing key, switch your backend to it, then revoke the old one. Multiple active keys are allowed, so you can cut over without downtime.
  • Revoke: tokens signed by a revoked key stop working immediately. Revoke right away if a key may have leaked.

On this page