I’m trying to start my expo local server, but get the following message in console:
An Expo user account is required to proceed.
How would you like to authenticate? Log in with an existing Expo account
Fetching the user profile failed
certificate has expired
It then prompts me to login with my Expo Account, but then gives me the following error:
Error: certificate has expired
at TLSSocket.<anonymous> (_tls_wrap.js:1105:38)
at emitNone (events.js:106:13)
at TLSSocket.emit (events.js:208:7)
at TLSSocket._finishInit (_tls_wrap.js:639:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:469:38)
This is a legacy ExpoKit (SDK 36) project that I am doing maintenance on, so the expo-cli version is 3.11.0. The reason this version is used is because of the following warning message: Your project is using deprecated "rnpm" config that will stop working from next release. Please use a "react-native.config.js" file to configure the React Native CLI. Migration guide: https://github.com/react-native-community/cli/blob/master/docs/configuration.md.
I have tried researching this and it appears it is on Expo’s end that something has changed. Can anyone help?
Hey @bertied, unfortunately we are unable to provide support for projects that fall outside of our support cycle. Is there a particular reason the project is being kept on SDK36/using ExpoKit at this time?
This is not about the credentials for signing an app but rather about the SSL certificate chain on exp.host and how your machine processes it.
I think that you do not have an up-to-date ISRG Root X1 CA certificate in your trusted root store. You might also need to upgrade the version of OpenSSL on your system (which I suppose would probably include recompiling/upgrading node or whatever you’re using to send push notifications.)
EDIT: Probably also a good idea to remove the expired “DST Root CA X3” certificate from your trust store as mentioned in the blog post from OpenSSL.org.
The most likely cause of this issue is that you’re using an older version of OpenSSL and an older set of root CA certificates, both of which are the case with no-longer-supported versions of Node.js.
(Today, Node 12.13.0 and up are supported by the Node.js team, which approximately matches Expo’s policy for supported versions of Node. In April 2022, Node 14.15.0 will be the oldest version supported by the Node.js team.)
Let’s Encrypt, the service we use for many of our TLS certificates, recently changed their root certificate from “DST Root CA X3”, which is now expired, to “ISRG Root X1”. For compatibility with older versions of Android (which a service like Expo especially needs!), the new ISRG Root X1 was cross-signed by DST Root CA X3. This causes issues with OpenSSL 1.0.x and is fixed in OpenSSL 1.1.0 and newer.
You can check the version of OpenSSL you’re using in Node.js with:
If you see an version number older than OpenSSL 1.1.0, this likely explains the issue.
The best solution in this case is to upgrade your version of Node. While upgrading to Node 16, the current version, is probably a good idea, you also can upgrade to Node 12. The latest version of Node 12.22.6 contains OpenSSL 1.1.1l and the newer root CA certificates.
The NODE_TLS_REJECT_UNAUTHORIZED environment variable disables all TLS verification, allowing any certificate, including malicious ones, to work. If you understand your threat model well, this footgun could be useful. However, upgrading Node is obviously more secure.
There is a conflict between old versions of OpenSSL and old versions of Android. The server can either stay as it is now, which will allow old versions of Android to continue working, or it can make the change you suggest and allow old versions of OpenSSL to work. There’s no way to get both old versions of OpenSSL and old versions of Android to work at the same time.
It seems that the Expo team has decided that it’s more important to support old versions of Android than old versions of OpenSSL. However, it could be that they had not considered your use case.
We’re using Let’s Encrypt’s recommended configuration, which they designed to keep Android apps working and is something we need to do. The DST Root CA X3 certificate is intentionally used to cross-sign the ISRG Root X1 certificate.
In this post, the Let’s Encrypt team explains the two certificate chains. There’s the longer one that is cross-signed with the DST Root CA X3 certificate and works with Android, and the shorter one that ends with the ISRG Root X1 certificate. The shorter chain doesn’t have the Android compatibility patch:
This is a shorter chain, available to people through the API who do not need the Android compatibility of the longer chain.
Android 5.x, which Expo currently supports, needs chains with the DST Root CA X3 certificate since ISRG Root X1 is not in the device’s certificate store. For this reason, we use the longer cross-signed certificate chain.
Software that doesn’t work with the cross-signed root CA certificate will need to be updated. For software that uses Node.js, upgrading to any version of Node that is currently supported by the Node.js team (that is, 12.13.0 and up) includes a working version of OpenSSL (1.1.0 or newer) and the ISRG Root X1 certificate.