Rotate signing keys
Grona signs two things that your app and your servers verify: the configuration and grants. Each has its own key pair, and both rotate the same way. The next public key ships in every verifier before Grona signs with it, and verifiers pick a key by its kid. This page gives the procedure, the bounds Grona signs within, and what to do if a key is exposed.
The two keys
Section titled “The two keys”| Key | Signs | Pinned in |
|---|---|---|
| Config key | Configurations and preview pins | Your app’s SDK options |
| Grant key | Grants | Your app’s SDK options and your order backend |
Each public key is a P-256 key as base64 DER SubjectPublicKeyInfo, with a key id such as acme-market-2026-10 for a config key or acme-market-grants-2026-10 for a grant key. Grona holds the private keys. It does not publish public keys at a URL, so there is no key set to download: Grona gives you the keys, and you pin them.
Keys reach the SDK only through your app’s options. A configuration cannot add or remove keys, so a key leaves an installed app only with an app release.
How verifiers pick a key
Section titled “How verifiers pick a key”Every configuration and every token names its key in the kid header field. The SDK and your order backend look the kid up in the keys they pin and reject any kid they do not know. Pinning two keys, the current one and the next one, is what lets Grona switch keys without breaking installed apps.
To set the keys in your app, see Initialise the SDK for Android or iOS. For your order backend, see Grants and order verification.
Rotate a key
Section titled “Rotate a key”-
Grona gives you the next public key and its
kid, for exampleacme-market-2027-04. -
Pin it as the next key, beside the current one. Pin a config key in your app. Pin a grant key in your app and in your order backend.
-
Deploy your backend, and release the app version that carries the next key.
-
Once that release has reached the installs you need, agree the switch with Grona. Grona then signs with the next key.
-
For a grant key, keep the old key in your order backend until every grant signed with it has expired. That is at most 24 hours after the switch, plus your clock leeway. Then remove it.
-
In your next app release, drop the old key and pin a new next key, so the following rotation is ready in advance.
Installs without the new key
Section titled “Installs without the new key”An install that never received the next key fails safe for the app and closed for money:
- Config key. The SDK rejects configurations signed with the new key. It keeps the last configuration it accepted until that one expires, and then renders nothing. It also ignores preview pins signed with the new key.
- Grant key. The SDK rejects grants signed with the new key, so offers do not render and campaigns leave their placements to the next campaign. The shopper’s orders still succeed.
Bounds Grona signs within
Section titled “Bounds Grona signs within”Grona signs within these rules. Many of them mirror checks the SDK runs, which would reject the configuration or leave its campaigns inactive:
issued_atfalls between 2020-01-01 and 2100-01-01, andexpires_atis afterissued_atand at most 400 days later. Remote configurations expire in days, not months.ttl_secondsis between 300 and 86,400, and 300 for configurations that carry money treatments.schemais 1, andversionis a positive integer that rises for each workspace and is never reused.versionis never a timestamp or another large number. The rollback check on each install is permanent, so one mistakenly high version would block every later configuration until the server’s versions passed it.- A bundled configuration never carries a version above the one the server serves.
- A
304 Not Modifieddoes not extendexpires_at, so Grona signs and serves a new version before the current one expires. Otherwise every device would freeze. - Grona never raises the top-level
min_sdkorschemawhile older SDKs are in the field. It setsmin_sdkon individual campaigns instead. - A configuration holds at most 200 campaigns, with unique ids, known placements, a unit of
installorcustomer, variant weights that sum to 10,000, holdouts between 0 and 10,000 basis points, and both salts set. A campaign with a money treatment uses thecustomerunit. settings.demois nevertruein a production configuration.- Grants and preview pins last at most 24 hours.
If a key is exposed
Section titled “If a key is exposed”Contact Grona at once through Get help. What you do next depends on the key.
Grant key
Section titled “Grant key”Remove its kid from your order backend’s keys. From then on, grants signed with it fail verification: no treatment is applied, and orders still succeed. Your order backend is where money is contained, so this step comes first.
Installed apps trust the key until an app release removes it. A forged grant could make an offer render on a device, but your backend never honours it. Pin the replacement key that Grona gives you in your backend and in your next app release.
Config key
Section titled “Config key”Installed apps trust every config key they pin until an app release removes it. A configuration signed with an exposed key passes the signature check on those installs. Such a configuration:
- could change which campaigns show and what they say, within the limits the SDK applies to every configuration: the add-to-basket caps, typed routes only, plain text only, and prices and product names from your app’s own data;
- could not create a grant, because grants need the separate grant key, so it could not make your backend apply a treatment;
- could sign preview pins, which use the config key;
- with an inflated
version, would hold back legitimate configurations on every install that accepted it, because the rollback check is permanent.
Ship an app release that pins the replacement key and drops the exposed one. There is no supported way yet to recover installs that accepted a forged configuration. Contact Grona through Get help.