Edit this page
Learn how code signing and key rotation work in EAS Update.
EAS Update Code Signing is only available to accounts subscribed to the EAS Production or Enterprise plans. Learn more.
The expo-updates
library supports end-to-end code signing using public-key cryptography. Code signing allows developers to cryptographically sign their updates with their own keys. The signatures are then verified on the client before the update is applied, which ensures ISPs, CDNs, cloud providers, and even EAS itself cannot tamper with updates run by apps.
The following steps will guide you through the process of generating a private key and corresponding certificate, configuring your project to use code signing, and publishing a signed update for your app.
1
In this step, we will generate a key pair and corresponding code signing certificate for your app. Specify a directory outside of your source control for the --key-output-directory
flag to ensure the generated private key isn't accidentally added to source control.
-
npx expo-updates codesigning:generate \
--key-output-directory ../keys \
--certificate-output-directory certs \
--certificate-validity-duration-years 10 \
--certificate-common-name "Your Organization Name"
This command generated a key pair along with a code signing certificate to be included in the app:
../keys/private-key.pem
: the private key of the key pair.
../keys/public-key.pem
: the public key of the key pair.
certs/certificate.pem
: the code signing certificate configured to be valid for 10 years. This file should be added to source control (if applicable).
The generated private key must be kept private and secure. The command above suggests generating and storing these keys in a directory outside of your source control to ensure they are not accidentally checked into source control. We recommend storing the private key in the same way you would store other sensitive information (KMS, password manager, and so on), and how you store it will vary the steps needed to publish an update in step (3).
The public key may be stored alongside the private key, but isn't sensitive.
The certificate should be included in the project (checked into source control). It contains the public key and a method for verifying code signatures. When a signed update is downloaded, the update's signature is verified using this certificate.
The certificate validity duration is a setting that may vary based on the security needs of your app.
2
-
npx expo-updates codesigning:configure \
--certificate-input-directory certs \
--key-input-directory ../keys
If you are using Continuous Native Generation (CNG) to generate your native projects, then the app.json configuration generated by the npx expo-updates codesigning configure
command is all that you need. The changes will be applied to the native projects the next time they are generated.
After running the above command, your app.json will include additional configuration for code signing:
{
"expo": {
"updates": {
"codeSigningCertificate": "./certs/certificate.pem",
"codeSigningMetadata": {
"keyid": "main",
"alg": "rsa-v1_5-sha256"
}
}
}
}
If you are not using Continuous Native Generation (CNG) to generate your native projects, then you will need to configure code signing in your app AndroidManifest.xml and/or Expo.plist files.
You will need to add two fields to the <application>
element in android/app/src/main/AndroidManifest.xml
Before doing that, we need to generate an XML-escaped version of your certificate. You can either copy the contents of certs/certificate.pem and replace all of the \r
characters with 
and \n
with 

manually, or run the following script to do that for you:
-
node -e "console.log(require('fs').readFileSync('./certs/certificate.pem', 'utf8')\
.replace(/\r/g, '
').replace(/\n/g, '
'));"
Now add the following two fields, and replace the android:value
for the expo.modules.updates.CODE_SIGNING_CERTIFICATE
field with the XML-escaped certificate. You do not need to modify the value for expo.modules.updates.CODE_SIGNING_METADATA
entry.
<meta-data
android:name="expo.modules.updates.CODE_SIGNING_CERTIFICATE"
android:value="(insert XML-escaped certificate here)"
/>
<meta-data
android:name="expo.modules.updates.CODE_SIGNING_METADATA"
android:value="{"keyid":"main","alg":"rsa-v1_5-sha256"}"
/>
You will need to add two fields to the <dict>
element in ios/project-name/Supporting/Expo.plist.
Before doing that, we need to generate an XML-escaped version of your certificate. You can either copy the contents of certs/certificate.pem and replace all of the \r
characters with 
, or run the following script to do that for you:
-
node -e "console.log(require('fs').readFileSync('./certs/certificate.pem', 'utf8')\
.replace(/\r/g, '
'));"
Now add the following two fields, and replace the certificate value with the XML-escaped certificate. You do not need to update the EXUpdatesCodeSigningMetadata
field.
<key>EXUpdatesCodeSigningCertificate</key>
<string>-----BEGIN CERTIFICATE-----
(insert XML-escaped certificate, it should look something like this)
(spanning multiple lines with \r escaped but \n not escaped)
+-----END CERTIFICATE-----
</string>
<key>EXUpdatesCodeSigningMetadata</key>
<dict>
<key>keyid</key>
<string>main</string>
<key>alg</key>
<string>rsa-v1_5-sha256</string>
</dict>
With code signing configured, create a new build with a new runtime version. The code signing certificate will be embedded in this new build.
3
-
eas update --private-key-path ../keys/private-key.pem
During an EAS Update publish using eas update
, the EAS CLI automatically detects that code signing is configured for your app. It then verifies the integrity of the update and creates a digital signature using your private key. This process is performed locally so that your private key never leaves your machine. The generated signature is automatically sent to EAS to store alongside the update.
4
Download the update on the client (this step is done automatically by the library). The build from step (2) that is configured for code signing checks if there is a new update available. The server responds with the update published in step (3) and its generated signature. After being downloaded but before being applied, the update is verified against the embedded certificate and included signature. The update is applied if the certificate and signature are valid, and rejected otherwise.
Key rotation is the process by which the key pair used for signing updates is changed. This is most commonly done in a few cases:
certificate-validity-duration-years
to 10 years (though it can be configured to any value). This means that after 10 years, updates signed with the private key corresponding to the certificate will no longer be applied after being downloaded by the app. Updates downloaded before the expiration of their signing certificate will continue to function normally. Rotating keys well before the certificate expires helps to preempt any potential key expiration issues and helps to guarantee all users are using the new certificate before the old certificate expires.In any of these cases, the procedure is similar:
keyid
of the new key by modifying the updates.codeSigningMetadata.keyid
field in your app config (app.json).The process of removing code signing from an app is similar to key rotation and can be thought of as a key rotation to a null
key.
updates.codeSigningMetadata
field from your app config (app.json).