Pub/sub Token Authorization
JWT access control for bidirectional realtime paths
Pub/sub Tokens
Scout exposes an authorization primitive for managing access control on bidirectional data streams. These short-lived JWTs scope publish put and subscribe get on herd id prefixes. You can use this pattern for any system that requires role based permissions for getting or putting data across a realtime channel (e.g. moq media streams, metadata websockets, etc).
Claims
| Claim | Role |
|---|---|
root | Base namespace (often "") |
put | Publish prefixes |
get | Subscribe prefixes |
iat / exp | Issued / expiry |
Verifiers use public JWKs like {kid}.jwk. Edge secrets: PUBSUB_JWT_PRIVATE_JWK (private JWK) and optional PUBSUB_TOKEN_TTL_SEC (default 3600 seconds; 60–86400).
Flow
- Client calls
mint-pubsub-token(user session, deviceapi_key, or service role). - Edge resolves claims as the caller —
get_pubsub_token_claims()for users/devices, orget_service_pubsub_token_claims(herd_ids)when the caller presents aservice_rolekey and an explicit herd scope — then signsput/get. - Client presents the JWT to your service.
- Service verifies the token and checks paths.
Service accounts
Trusted backends (e.g. the video ingest relay) mint publish-only tokens without a device row. They authenticate with the Supabase service_role key and pass an explicit herd_ids scope in the request body. The private signing key stays in the edge function, so no key material is handed to the relay.
Who Gets What Claims
RPC is SECURITY INVOKER (same identity as the minter).
| Caller | put | get | Mint |
|---|---|---|---|
| Platform superadmin | [""] | [""] | Yes — all paths |
User with realtime_streams.write per herd | those herd ids | ids with realtime_streams.read | Yes |
| User with read only | [] | ids with realtime_streams.read | Subscribe only |
| Device API key | device herd id | same | Yes |
Service role (explicit herd_ids) | those herd ids | [] | Publish only |
| User, no stream abilities | — | — | No (null → 401) |
| Unauthenticated | — | — | No |
"" unlocks the full path tree. Prefix match is greedy, so for example hey unclocks hey/A and hey/A/B/C/1/2/3.
Database
| Object | Role |
|---|---|
pubsub_jwt_public_keys | Active public JWKs by kid |
get_pubsub_jwt_public_keys() | Keys for verifiers |
upsert_pubsub_jwt_public_key | Register / rotate (requires service role or superadmin) |
revoke_pubsub_jwt_public_key | Soft-revoke |
get_pubsub_token_claims() | Mint only — user / device claims |
get_service_pubsub_token_claims(herd_ids) | Mint only — service-role publish scope |
The last two functions allow for programmatic rotation of the public verification key. Scout RS exposes rotation helpers, so edge services can auto-upgrade.
As a scout database admin, your key rotation flow should look sometjing like: upsert public key → sync verifiers → update edge private JWK → wait TTL → revoke old kid.