Skip to content
The mobile SDKs are available on request. Email support@grona.ai to get access.

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.

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.

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.

  1. Grona gives you the next public key and its kid, for example acme-market-2027-04.

  2. 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.

  3. Deploy your backend, and release the app version that carries the next key.

  4. Once that release has reached the installs you need, agree the switch with Grona. Grona then signs with the next key.

  5. 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.

  6. In your next app release, drop the old key and pin a new next key, so the following rotation is ready in advance.

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.

Grona signs within these rules. Many of them mirror checks the SDK runs, which would reject the configuration or leave its campaigns inactive:

  • issued_at falls between 2020-01-01 and 2100-01-01, and expires_at is after issued_at and at most 400 days later. Remote configurations expire in days, not months.
  • ttl_seconds is between 300 and 86,400, and 300 for configurations that carry money treatments.
  • schema is 1, and version is a positive integer that rises for each workspace and is never reused.
  • version is 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 Modified does not extend expires_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_sdk or schema while older SDKs are in the field. It sets min_sdk on individual campaigns instead.
  • A configuration holds at most 200 campaigns, with unique ids, known placements, a unit of install or customer, 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 the customer unit.
  • settings.demo is never true in a production configuration.
  • Grants and preview pins last at most 24 hours.

Contact Grona at once through Get help. What you do next depends on the 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.

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.