Skip to content

SDK code signing

With code signing, every release is signed with your private key and every device verifies the signature before installing. An update that does not verify is rejected.

Add the PEM public key to the native configuration. iOS, in Info.plist:

<key>CodePushPublicKey</key>
<string>-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----</string>

Android, in strings.xml:

<string moduleConfig="true" name="CodePushPublicKey">-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----</string>

On iOS there is deliberately no runtime setter: the key lives only in Info.plist, so an attacker cannot swap it from JavaScript.

Each signed release ships a .codepushrelease file: a JWT signed with RS256 over the content hash of the update. The device recomputes the hash of what it downloaded, verifies the JWT against the configured public key, and installs only when both match.

Sign with the CLI: aether release-react MyApp ios --privateKeyPath keys/private.pem, or aether release --privateKeyPath for pre-built contents. Signed contents must live in a folder named CodePush; the CLI enforces this because devices look for the signature and hash file paths under that exact name.

Once a CodePushPublicKey is configured, unsigned updates fail verification on that binary. Roll signing out with a new binary release, then sign every OTA update targeting it.