Signing Keys
Your app decides who may publish and watch, and signs that decision as a short-lived
credential. It signs with an Ed25519 signing key that it generates and keeps; Qumo
stores only the public half. A relay admits a credential only when its key is registered
and every path it grants lies within the key’s prefix.
Managed relays start accepting credentials from registered keys in an upcoming release.
Until then, registering a key has no effect on them.
Managed relays trust a key only while its project is a prod project and its workspace’s
plan includes the managed relay network. If the workspace moves to a plan without it, its
keys stop being trusted within about a minute, which ends their sessions; they are trusted
again when the plan is restored, with nothing to register again. The same holds while
Qumo has suspended a project (suspended_at on the project): its keys stay registered
and are trusted again when it is resumed.
The prefix
Every project has a root, <workspace slug>/<project slug>, for example
acme/live-app. The API returns both slugs (slug on the workspace and the project), and
they never change, even when you rename either. A key is confined to the project root, or
to a narrower path under it that you choose at registration (live gives
acme/live-app/live). A credential that grants a path outside the key’s prefix is refused.
Create a key
One step generates a key on your machine, registers its public half, and gives you the
private key. The private key is never sent to Qumo, and what you get is its only copy.
With the CLI:
--prefix is optional and relative to the project root. signing-key.jwk is written
owner-only and is never overwritten.
With the SDK:
Either way the private key is a JWK carrying its kid and prefix, the file
qumo auth token and the Go token package sign with. Keep it on your app’s server.
Register a key you already have
To generate the key yourself, use the qumo CLI. Pass the prefix the key will be
registered with, so qumo auth token and the token package refuse to sign outside it:
signing-key.jwk holds the private key. Keep it on your app’s server.
Registration proves you hold the private key: you sign a dated message with it and send
the signature with the public key, in one request. The SDK does this, signing locally; the
private key is never sent:
Without the SDK, POST /v1/projects/{id}/signing-keys with
{"name", "public_key": {"kty": "OKP", "crv": "Ed25519", "x"}, "prefix", "signed_at", "signature"}:
signed_at is the current time in unix seconds, and signature is the Ed25519 signature,
base64url without padding, over the string
qumo-signing-key-registration:<project id>:<signed_at>. It is accepted within five
minutes of signed_at.
A project holds at most five active keys. A key is registered once across Qumo:
registering the same public key again, in any project, is refused.
Rotation and revocation
A key is active until you revoke it
(POST /v1/projects/{id}/signing-keys/{kid}/revoke). Revoking is final: managed relays stop
trusting the key within about a minute, which ends the sessions it admitted, and the key
can’t be registered again.
To rotate without interrupting anyone: create the new key, wait a minute, and switch
your app to sign with it. An hour later, once the last credential signed with the old key
has expired, revoke the old key.
If a private key may be exposed, revoke it at once. Its live sessions end; your clients
reconnect with credentials from another key.
Permissions
Listing keys needs signing_key.list; registering and revoking need
signing_key.manage. For Identity Tokens, the scopes are project:read and
signing_keys:admin. See Scopes & Permissions.