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:
- Turn on token access for the organization.
- 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
}expis mandatory: a token without it is rejected.subbinds the token to one video. A token presented for any other video is rejected.- Mint a fresh token per playback session and keep
expshort (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_JWTOutcomes
| Situation | Result |
|---|---|
| Valid token | Plays; assets returned as short-lived signed URLs |
| Missing / invalid / expired token | 401 (player shows a blocked message) |
| Token for a different video | 403 |
| Token signed by a revoked key | 401 |
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.