Skip to content

Tokens ​

Mint media tokens that let publishers and viewers connect, scoped to the broadcasts and time you choose.

Two kinds of credential ​

  • An account token calls the management API. Create one under API Tokens or with POST /v1/account/tokens, choosing a none, read, or write level per permission family and, optionally, the projects it reaches. Each operation in the API reference names the permission it needs. MCP clients and other agents sign in as the agent guide describes.
  • A media token is a JWT that a publisher or viewer presents to the relay, usually as the jwt query parameter. A signing key on the project mints it, and it grants nothing in the management API.

The rest of this page is about media tokens. The commands reuse API, MOQ_API_TOKEN, PID, and KID from the quickstart.

Scope a token ​

A media token carries four claims:

ClaimMeaning
rootThe path every pattern is relative to, which the client must dial. It defaults to the project id, so clients connect to https://cdn.moq.pro/<project id>; a limited key may default it to a deeper path.
publishPatterns the client may publish.
subscribePatterns the client may watch.
expWhen the token stops working. The API allows up to 30 days, or no expiry if omitted.

A pattern names exactly what it says: room/alice.hang is one broadcast, room/** is everything under room, and ** is everything under the root. A token that grants nothing is refused.

Prefer short expiries, and mint a fresh token per viewer or per page load.

Mint with the API ​

The API signs with a key it holds, so your server never handles signing material. This grants one viewer room/alice.hang for ten minutes:

sh
EXPIRES=$(($(date +%s) + 600))
BODY=$(jq -nc --argjson exp "$EXPIRES" \
  '{subscribe: ["room/alice.hang"], exp: ($exp | todate)}')
VIEW_TOKEN=$(curl --fail-with-body --silent --show-error "$API/projects/$PID/keys/$KID/token" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: \"tokens-view-$EXPIRES\"" \
  --data "$BODY" | jq -er '.token')

The account token needs keys:write. Each request needs an Idempotency-Key; derive it from the claims, as here, so a retry returns the same token and a new mint gets a new key.

Mint on your own server ​

To mint without a request per token, download a symmetric key once and sign locally:

sh
curl --fail-with-body --silent --show-error "$API/projects/$PID/keys/$KID/private" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" | jq -er '.privateKey' > key.jwk

Anyone with key.jwk can mint any token for the project, so keep it with your other secrets. Sign with the moq auth command, the @moq/auth package, or the moq-auth crate. The dashboard's Tokens page writes the code for the claims you pick.

You can also import a key you generated yourself with POST /v1/projects/{pid}/keys/import, including an asymmetric one whose private half never leaves your server.

Limit a key ​

A key created with publish or subscribe patterns can only mint tokens inside them, and the API refuses a mint that reaches outside. Give each service the narrowest key it needs:

sh
curl --fail-with-body --silent --show-error "$API/projects/$PID/keys" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: "tokens-viewer-key-1"' \
  --data '{"algorithm":"HS256","label":"Viewers","subscribe":["**"]}'

Revoke ​

Disabling a key refuses new connections with any token it signed. Enable it again, or delete it once disabled. The project's Keys page does the same.

sh
curl --fail-with-body --silent --show-error -X POST "$API/projects/$PID/keys/$KID/disable" \
  -H "Authorization: Bearer $MOQ_API_TOKEN"

Public access ​

Public access lets anyone publish or watch matching paths with no token. This opens every broadcast in the project for watching:

sh
curl --fail-with-body --silent --show-error -X PATCH "$API/projects/$PID" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"public":{"v":1,"subscribe":["**"]}}'

Patterns are relative to the project. Send "public": null to turn it off, or use the project's Public access page.

Your own auth server ​

Instead of minting tokens, a project can ask your HTTPS endpoint whether to admit each session. Set it on the project's Auth endpoint page or with PUT /v1/projects/{pid}/auth/endpoint. The CDN signs every request the way it signs webhooks, and your endpoint answers with the same grant a token carries, following upstream's auth contract. The dashboard page lists what the CDN sends and what it accepts back.