Expo Go code signing works by using the following mechanism: https://github.com/expo/code-signing-certificates/pull/1
- Expo Go root certificate embedded in the Expo Go application. Valid for 40 years. Private key kept offline.
- Expo Go intermediate certificate downloaded by @expo/cli
. Valid for 2 years. Private key kept on signing server. This is a child certificate of the Expo Go root certificate.
- Expo Go development certificate generated and downloaded by @expo/cli
. When a project is started (npx expo start
) we sign the project manifest to ensure scoped module impersonation isn’t possible within Expo Go (accessing scoped modules for other projects run in Expo Go). To do this signing, a private key and certificate signing request is generated. This CSR is sent to the expo signing server, and a development certificate valid for 30 days is returned. This development certificate is a child of the Expo Go intermediate certificate.
Then, when Expo Go loads an app, it checks that this certificate chain is valid (all certificates are valid and lineage is correct).
The incident here was that, while we had planned to refresh the Expo Go intermediate certificate every year to preempt the 2 year validity expiration, it was overlooked. So the Expo Go intermediate certificate expired and therefore the certificate chain was invalid. Note that this only affected projects in local development.
The fix was to re-generate a new Expo Go intermediate certificate from our root certificate (https://github.com/expo/code-signing-certificates/pull/14) and then update the certificates on the signing server. After the signing server updates were deployed to production, all future requests for a development signing certificate now use the new intermediate certificate.
Users still seeing issues should ensure they are not using the --offline
flag (at least once) when running npx expo start
to get a new development certificate with the updated intermediate certificate.