HotCodePush

Sign your bundles

Create a signing key pair, ship a build that trusts it, sign every upload in CI and rotate or retire keys without breaking devices in the field.

Signing makes a device apply nothing your team did not sign. The key is yours: the CLI signs the bundle manifest at upload with a private key on your machine. The device verifies the signature over the bytes it downloaded before it applies anything.

The private key never reaches HotCodePush, and signing is opt-in and available on every plan. The signature covers the bundle, not the channel index. How an update reaches a device says what an unsigned index can and cannot do. The short version is the site's OTA update security page.

Prerequisites

  • Quickstart has run, so the SDK is installed and a first release is live.
  • The CLI is signed in, or HOTCODEPUSH_TOKEN is in the environment.
  • You hold the Owner or Admin role on the app. Organizations lists the roles.

1. Create a signing key pair

If init already generated one for you, skip to step 2. Run the command in the project root:

npx hotcodepush signing-key create

The CLI generates an RSA key pair on your machine and registers the public key with the app. It appends the key to publicKeys in hotcodepush.json and writes the private key to hotcodepush-private-key.pem, never printing it. A pair the team already holds, such as a CodePush app's key, is added with signing-key add instead.

The console's Signing keys page lists keys and deletes them, while the pair is generated on your machine.

Keep the private key out of version control

Add hotcodepush-private-key.pem to .gitignore before the next commit. Whoever holds the file can sign the app's bundles. CI holds the file's content as a secret, never the file in the repository.

2. Ship a store build that trusts the key

signing-key create wrote the public key into hotcodepush.json:

hotcodepush.json
{
  "appId": "7f3c2d1e-9a4b-4c5d-8e6f-0a1b2c3d4e5f",
  "channel": "production",
  "publicKeys": [
    "rsa-v1_5-sha256:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA…"
  ]
}

The build step writes every listed key into the binary, so a binary trusts the keys listed when it was built. Ship a store build with the list in place.

A binary with a key refuses an unsigned or wrongly signed bundle and keeps the one it runs. A binary built with an empty list checks the content hashes alone, so the signed uploads of step 3 reach older binaries too.

3. Sign every upload

Once a public key is registered, an unsigned upload for the app is refused. Every release create and bundle upload now carries the key:

npx hotcodepush release create --path dist --private-key-path hotcodepush-private-key.pem

In CI, store the file's content as the secret HOTCODEPUSH_SIGNING_KEY. The CLI reads it when --private-key-path is absent. Ship every commit shows where both secrets go. A pull-request pipeline that runs release create --dry-run signs nothing and needs no key.

The release applies within about a minute. If nothing happens, see Troubleshooting.

4. Rotate a key

Rotation is a store release, in this order, since a binary that trusts only the old key refuses a bundle signed with the new one:

  1. Create the second key with npx hotcodepush signing-key create --private-key-path hotcodepush-private-key-2.pem. It is appended to publicKeys, so every build from now on trusts both keys.
  2. Ship a store build.
  3. Keep signing with the old key while binaries that trust only it still have devices. binary list shows each binary with its device count.
  4. Switch to the new key, through --private-key-path or the HOTCODEPUSH_SIGNING_KEY secret.
  5. Delete the old key with npx hotcodepush signing-key delete once no binary that trusts only it has devices.

To leave signing, ship a store build whose publicKeys is empty, keep signing while binaries that trust the keys still have devices, then delete every key. The CLI signs only while the hotcodepush.json it reads lists the key, so during that window release with --config pointing at a copy that still lists it.

A mistaken delete is reversed with signing-key add, as long as the team holds the private key.

Next steps

Last updated on

On this page