Skip to content

Authenticate Media and Streams

How to authenticate Rhombus snapshots, exact frames, clip downloads, live and recorded HLS, DASH and WebSocket streams, shared stream links and LAN streams, from servers, native apps and browsers.

On this page

Media (snapshots, frames, clips, live and recorded video, audio) comes from the media hosts, not the REST API, and the URLs the API returns carry no credential. You add one to every request. Three rules cover almost everything:

  1. From your server or a native app, send your API key as headers (x-auth-scheme: api-token and x-auth-apikey), or an OAuth access token as Authorization: Bearer <token>.
  2. From a browser (an <img>, a <video>, a JavaScript player or a WebSocket), send a federated token as query parameters: ?x-auth-scheme=federated-token&x-auth-ft=<token>. API keys and OAuth access tokens can't be sent in a URL.
  3. Cameras on your local network accept federated tokens only. That's deliberate: on the local network, every request carries a short-lived token you can limit to one camera. See Streaming over LAN.

Hosts

WhatUS hostNotes
Snapshots, frames, clip downloadsmedia.rhombussystems.comEU: media.eu.rhombussystems.com
Live and recorded streamsPer-camera hosts such as <id>.dash.rhombussystems.com, returned by getMediaUrisSome requests to media.rhombussystems.com redirect (307) to the camera's host; follow redirects
Cameras on your LAN<camera>.lan.rhombussystems.com:8000Public DNS for a private address; use the hostname, not the IP

Credentials are region-bound: a US key or token doesn't work on EU hosts.

Snapshots and exact frames

The latest snapshot of a camera:

https://media.rhombussystems.com/media/{cameraUuid}/{mediaRegion}/snapshot.jpeg

cameraUuid and mediaRegion come from getMinimalCameraStateList.

bash
curl "https://media.rhombussystems.com/media/CAMERA_UUID/MEDIA_REGION/snapshot.jpeg" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -o snapshot.jpeg

For a frame at a specific time, call getExactFrameUri (timestamps in milliseconds). The URI it returns is not signed: fetch it with the same headers, or append the same query parameters in a browser.

Saved clip downloads

Saved clips (from spliceV3 or the console) are downloaded from the media host by region and clip UUID. Take the region from the clip's clipLocation:

bash
curl "https://media.rhombussystems.com/media/metadata/{clipLocation.region}/{clipUuid}.mp4" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: $RHOMBUS_API_KEY" \
  -o clip.mp4

Use /media/play/{region}/{clipUuid}.mp4 instead to stream it inline (it supports Range requests). The credential's role needs permission to view saved video. A device-scoped federated token can fetch a saved clip only when every camera in the clip is the token's device.

Live and recorded video

POST /api/camera/getMediaUris returns the stream URLs for a camera:

FieldFormatUse it with
wanLiveM3u8UriHLSSafari <video>, hls.js, AVPlayer, ExoPlayer, ffmpeg
wanLiveMpdUriDASHdash.js
wanLiveH264UriH.264 over WebSocket (lowest latency)A custom decoder, or the React SDK
wanVodM3u8UriTemplate, wanVodMpdUriTemplateRecorded HLS / DASHReplace {START_TIME} (Unix time, seconds) and {DURATION} (seconds)
lan… fieldsThe same formats on your LANSee Streaming over LAN

Call getMediaUris with the credential your player will use, then authenticate each format as follows.

HLS

Add the token to the playlist URL. On the cloud hosts, the playlist carries the token's query parameters to every segment URL, so players need nothing else:

javascript
const url = `${wanLiveM3u8Uri}?x-auth-scheme=federated-token&x-auth-ft=${token}`;
if (video.canPlayType("application/vnd.apple.mpegurl")) {
  video.src = url; // Safari
} else {
  const hls = new Hls();
  hls.loadSource(url);
  hls.attachMedia(video);
}

From a native app or server, send the API key headers or Authorization: Bearer on every request instead.

DASH

Add the token to the manifest URL. On the cloud hosts, live and recorded DASH manifests (and alert clip manifests) carry the token's query parameters to every segment URL, so one URL works in any player:

javascript
const url = `${wanLiveMpdUri}?x-auth-scheme=federated-token&x-auth-ft=${encodeURIComponent(token)}`;
const player = dashjs.MediaPlayer().create();
player.initialize(video, url, true);

Only federated-token and shared-link query parameters are carried to segments. API keys and x-auth-org are never copied into segment URLs, so a server or native client sends its headers on every request.

For streams from a camera on your LAN, add the token to every request yourself. With dash.js 5, a request interceptor does it, and leaves alone any URL that already carries the token:

javascript
const auth = `x-auth-scheme=federated-token&x-auth-ft=${encodeURIComponent(token)}`;
const withAuth = (url) => (url.includes("x-auth-ft=") ? url : `${url}${url.includes("?") ? "&" : "?"}${auth}`);

const player = dashjs.MediaPlayer().create();
player.addRequestInterceptor((request) => {
  request.url = withAuth(request.url);
  return Promise.resolve(request);
});
player.initialize(video, lanLiveMpdUris[0], true);

WebSocket (H.264 and audio)

In a browser, put the token in the URL; from a server or native app, headers work too, as does an OAuth access token in Authorization: Bearer:

javascript
const ws = new WebSocket(`${wanLiveH264Uri}?x-auth-scheme=federated-token&x-auth-ft=${token}`);
ws.binaryType = "arraybuffer";

A token minted with a domain works here: browsers send Origin on the WebSocket handshake. See The domain field.

Open media sockets (live video, talk, robot and PTZ) close with code 1008 within 60 seconds when their credential is revoked or its access changes. With an OAuth token, talk audio is checked per message, and sending audio without the physical scope closes the socket with 1008 (OAuth scopes).

The robot live socket accepts API keys, OAuth access tokens and federated tokens, the same way.

Partner keys

A partner calling a client organization's media from a server sends its partner credential as headers (x-auth-scheme: api-token with x-auth-apikey, or Authorization: Bearer with a partner OAuth token) plus x-auth-org: <client org UUID>. x-auth-org is a header only and is never copied into segment URLs. For a browser, mint a federated token for the client organization (send x-auth-org when you mint).

createSharedLiveVideoStream creates a link to one camera's live video that works without any Rhombus credential:

  • sharedLiveVideoStreamUrl opens a Rhombus player page; embed it in an <iframe>.
  • sharedLiveM3U8StreamUrl is a raw HLS playlist for your own player.

Anyone who has the link can watch, so treat it like a password:

  • expirationTimeSecs is the Unix time (in seconds) when the link stops working, not a duration. Leave it out and the link never expires.
  • Password-protected links (createProtectedSharedLiveVideoStream): the player page asks for the password; for the raw HLS URL, send Authorization: Basic <base64(":" + password)> (an empty user name). A missing or wrong password returns 401 with WWW-Authenticate: Basic.
  • Delete the share (deleteSharedLiveVideoStream) to stop it immediately.

Troubleshooting

SymptomLikely causeFix
403 DOMAIN_NOT_ALLOWED on a media URLThe token was minted with a domain that isn't the page's exact origin (scheme, host, port), or the request carries no Origin or Referer (a server, a native player, a page with Referrer-Policy: no-referrer)Mint with your page's exact origin, or without domain for clients outside a browser
401 on a media URLThe credential is missing, damaged, expired or revoked; errorCode says whichSend the credential on every request, or mint a fresh token (Reading authentication errors)
A LAN DASH manifest loads, segments failSegment requests have no tokenAdd it to every request (see DASH)
Works on US hosts, fails on EU hostsKeys and tokens are region-boundMint in the same region as the camera
A device-scoped token fails on api2deviceUUid tokens only work for mediaUse an unscoped token for REST calls
403 with a device-scoped token on a clip or a shared linkThe clip includes other cameras, or the URL names no deviceMint an unscoped token for those requests
403 on a clip downloadThe role can't view saved video, or the region in the URL is wrongCheck the role and clipLocation
A media WebSocket closes with code 1008The credential was revoked or its access changed, or an OAuth token without physical sent talk audioReconnect with a valid credential, or request the physical scope
A shared link stopped workingexpirationTimeSecs was a duration (an already-past Unix time)Send a Unix time in seconds