Skip to content

Rotate a signing key

Rotate a product’s signing key when you want to move to a new one, or when the current one has leaked. A build of your app embeds one public key, and a build you already shipped cannot be changed. So plan a rotation together with your releases. Rotating takes one click in the Console, or one call to the Admin API; the work is in the order you do things around it.

Sealcord generates a new Ed25519 key for the product, stores it encrypted and never shows the private half. From that moment:

  • Every new licence key and every verdict is signed with the new key.
  • The old public key moves to the product’s previous public keys, and keys signed with it keep activating, unless you chose to stop accepting them.
  • A key you read back from a licence is signed again with the current key, so it is the one to send a customer who needs a key their new build accepts.
  • A build that holds only the old public key cannot check keys or verdicts signed with the new one.
  1. Rotate together with a new major version of your app. An owner or admin rotates the key in the Console, on the product’s page, with Rotate signing key, and keeps accepting the earlier keys. Or call the rotate route with { "keep_previous": true }, which needs the products:write scope. Builds that embed the old public key now reject new keys and verdicts, so ship the next step before you tell customers to update.
  2. Ship the build that embeds the new public key. Read it from the product’s page in the Console, or from public_key in the product’s answer. Customers on older builds keep the keys they have.
  3. Re-issue keys to customers who move to the new build. Reading a licence through the Admin API, or opening it in the Console, gives its key under the current signing key.
  4. Retire the old public key only when no build you support still uses it. In the Console, use Stop accepting on the earlier key; or call the retire route with { "public_key": "<64 hex characters>" }. Keys signed with it then stop activating within 30 seconds, with licence_key_invalid. Builds already shipped still accept those keys offline, and machines keep the verdict they hold until it expires. Re-issue keys to customers still on the old key first.

The current key cannot be retired: rotate first, or the call answers 409 conflict. Retiring a key that the product does not accept answers 404 public_key_not_found.

Terminal window
curl https://api.sealcord.com/v1/admin/products/acme-notes/rotate-signing-key \
-H "authorization: Bearer $SEALCORD_TOKEN" \
-H 'content-type: application/json' \
-d '{ "keep_previous": true }'

The answer is the product, with its new public_key, the old one in previous_public_keys, and its key_history.

Rotate with { "keep_previous": false } at once. Every key signed with the leaked key stops activating within 30 seconds of the rotation, and the API answers licence_key_invalid for it. If the leaked key is already a previous one, retire it instead.

Then ship a build with the new public key and re-issue keys to your paying customers. Builds you already shipped keep accepting keys signed with the leaked key offline, because they cannot know it leaked; only the API refuses them.

A product’s answer carries two fields that help during a rotation:

  • signing_key_status is ready when the API opens the private key and it matches the pinned public key. When it is unavailable, issuing and activating for the product answer product_unavailable.
  • key_history lists the keys the product accepts, the current one first. Each has its public_key, a fingerprint (the first 16 hex characters of the SHA-256 of the key, to tell keys apart at a glance), current, since and replaced_at.

The Console shows the same history on the product’s page, naming each key by its fingerprint.

On the API instance that handled the call, at once. Another instance picks it up within 30 seconds, because each keeps a copy of the product catalogue for that long. For that time it can still sign with, and accept keys under, the previous key.

Only if you retire the old public key, or rotate without keeping it. While the old key is accepted, existing keys keep activating. A customer needs a new key to use a build that embeds only the new public key.

No. Rotating again generates yet another key; it does not bring an old one back. Retiring a public key cannot be undone either, so check that no supported build uses it first.

No. Sealcord generates and stores each product’s signing key, and the private half is never shown or returned, so nobody can issue keys for your product outside Sealcord.