Skip to main content

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.