1--- 2title: Use local credentials 3description: Learn how to configure and use local credentials when using EAS. 4--- 5 6import ImageSpotlight from '~/components/plugins/ImageSpotlight'; 7import { Terminal } from '~/ui/components/Snippet'; 8 9You can usually get away with not being a code signing expert by [letting EAS handle it for you](managed-credentials.mdx). However, there are cases where some users might want to manage their project keystore, certificates and profiles on their own. 10 11If you would like to manage your own app signing credentials, you can use **credentials.json** to give EAS Build relative paths to the credentials on your local file system and their associated passwords to use them to sign your builds. 12 13## credentials.json 14 15If you opt-in to local credentials configuration, you'll need to create a **credentials.json** file at the root of your project and it should look something like this: 16 17```json credentials.json 18{ 19 "android": { 20 "keystore": { 21 "keystorePath": "android/keystores/release.keystore", 22 "keystorePassword": "paofohlooZ9e", 23 "keyAlias": "keyalias", 24 "keyPassword": "aew1Geuthoev" 25 } 26 }, 27 "ios": { 28 "provisioningProfilePath": "ios/certs/profile.mobileprovision", 29 "distributionCertificate": { 30 "path": "ios/certs/dist-cert.p12", 31 "password": "iex3shi9Lohl" 32 } 33 } 34} 35``` 36 37> Remember to add **credentials.json** and all of your credentials to **.gitignore** so you don't accidentally commit them to the repository and potentially leak your secrets. 38 39### Android credentials 40 41If you want to build an Android app binary you'll need to have a keystore. If you don't have a release keystore yet, you can generate it on your own using the following command (replace `KEYSTORE_PASSWORD`, `KEY_PASSWORD`, `KEY_ALIAS` and `com.expo.your.android.package` with the values of your choice): 42 43<Terminal 44 cmd={[ 45 '$ keytool \\', 46 ' -genkey -v \\', 47 ' -storetype JKS \\', 48 ' -keyalg RSA \\', 49 ' -keysize 2048 \\', 50 ' -validity 10000 \\', 51 ' -storepass KEYSTORE_PASSWORD \\', 52 ' -keypass KEY_PASSWORD \\', 53 ' -alias KEY_ALIAS \\', 54 ' -keystore release.keystore \\', 55 ' -dname "CN=com.expo.your.android.package,OU=,O=,L=,S=,C=US"', 56 ]} 57 cmdCopy='keytool -genkey -v -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -storepass KEYSTORE_PASSWORD -keypass KEY_PASSWORD -alias KEY_ALIAS -keystore release.keystore -dname "CN=com.expo.your.android.package,OU=,O=,L=,S=,C=US"' 58/> 59 60Once you have the keystore file on your computer, you should move it to the appropriate directory. We recommend you keep your keystores in the `android/keystores` directory. **Remember to git-ignore all your release keystores!** If you've run the above keytool command and placed the keystore at `android/keystores/release.keystore`, you can ignore that file by adding the following line to `.gitignore`: 61 62```sh .gitignore 63android/keystores/release.keystore 64``` 65 66Create **credentials.json** and configure it with the credentials: 67 68```json credentials.json 69{ 70 "android": { 71 "keystore": { 72 "keystorePath": "android/keystores/release.keystore", 73 "keystorePassword": "KEYSTORE_PASSWORD", 74 "keyAlias": "KEY_ALIAS", 75 "keyPassword": "KEY_PASSWORD" 76 } 77 }, 78 "ios": { 79 /* @hide ... */ 80 /* @end */ 81 } 82} 83``` 84 85- `keystorePath` points to where the keystore is located on your computer. Both relative (to the project root) and absolute paths are supported. 86- `keystorePassword` is the keystore password. If you've followed the previous steps it's the value of `KEYSTORE_PASSWORD`. 87- `keyAlias` is the key alias. If you've followed the previous steps it's the value of `KEY_ALIAS`. 88- `keyPassword` is the key password. If you've followed the previous steps it's the value of `KEY_PASSWORD`. 89 90### iOS credentials 91 92There are a few more prerequisites for building the iOS app binary. You need a paid Apple Developer Account, and then you'll need to generate the Distribution Certificate and Provisioning Profile for your application, which can be done via the [Apple Developer Portal](https://developer.apple.com/account/resources/certificates/list). 93 94Once you have the Distribution Certificate and Provisioning Profile on your computer, you should move them to the appropriate directory. We recommend you keep them in the `ios/certs` directory. In the rest of this document we assume that they are named **dist.p12** and **profile.mobileprovision** respectively. 95 96> Remember to add directory with your credentials to **.gitignore**, so you don't accidentally commit them to the repository and potentially leak your secrets. 97 98If you've placed the credentials in the suggested directory, you can ignore those files by adding the following line to **.gitignore**: 99 100```sh .gitignore 101ios/certs/* 102``` 103 104Create (or edit) **credentials.json** and configure it with the credentials: 105 106```json credentials.json 107{ 108 "android": { 109 /* @hide ... */ 110 /* @end */ 111 }, 112 "ios": { 113 "provisioningProfilePath": "ios/certs/profile.mobileprovision", 114 "distributionCertificate": { 115 "path": "ios/certs/dist.p12", 116 "password": "DISTRIBUTION_CERTIFICATE_PASSWORD" 117 } 118 } 119} 120``` 121 122- `provisioningProfilePath` points to where the Provisioning Profile is located on your computer. Both relative (to the project root) and absolute paths are supported. 123- `distributionCertificate.path` points to where the Distribution Certificate is located on your computer. Both relative (to the project root) and absolute paths are supported. 124- `distributionCertificate.password` is the password for the Distribution Certificate located at `distributionCertificate.path`. 125 126#### Multi-target project 127 128If your iOS app is using [App Extensions](https://developer.apple.com/app-extensions/) like Share Extension, Widget Extension, and so on, you need to provide credentials for every target of the Xcode project. This is necessary because each extension is identified by an individual bundle identifier. 129 130Let's say that your project consists of a main application target (named `multitarget`) and a Share Extension target (named `shareextension`). 131 132<ImageSpotlight 133 alt="Xcode multi target configuration" 134 src="/static/images/eas-build/multi-target.png" 135 style={{ maxWidth: 360 }} 136/> 137 138In this case, your **credentials.json** should look like below: 139 140{/* prettier-ignore */} 141```json credentials.json 142{ 143 "ios": { 144 "multitarget": { 145 "provisioningProfilePath": "ios/certs/multitarget-profile.mobileprovision", 146 "distributionCertificate": { 147 "path": "ios/certs/dist.p12", 148 "password": "DISTRIBUTION_CERTIFICATE_PASSWORD" 149 } 150 }, 151 "shareextension": { 152 "provisioningProfilePath": "ios/certs/shareextension-profile.mobileprovision", 153 /* @info You can use either the same distribution certificate (as for the first target) or a new one */ 154 "distributionCertificate": { 155 "path": "ios/certs/another-dist.p12", 156 "password": "ANOTHER_DISTRIBUTION_CERTIFICATE_PASSWORD" 157 } 158 /* @end */ 159 } 160 } 161} 162``` 163 164## Setting a credentials source 165 166You can tell EAS Build how it should resolve credentials by specifying `"credentialsSource": "local"` or `"credentialsSource:" "remote"` on a build profile. 167 168- If `"local"` is provided, then **credentials.json** will be used. 169- If `"remote"` is provided, then credentials will be resolved from EAS servers. 170 171For example, maybe you want to use local credentials when deploying to the Amazon Appstore and remote credentials when deploying to the Google Play Store: 172 173```json eas.json 174{ 175 "build": { 176 "amazon-production": { 177 "android": { 178 "credentialsSource": "local" 179 } 180 }, 181 "google-production": { 182 "android": { 183 "credentialsSource": "remote" 184 } 185 } 186 } 187} 188``` 189 190If you do not set any option, `"credentialsSource"` will default to `"remote"`. 191 192## Using local credentials on builds triggered from CI 193 194Before you start setting up your CI job, make sure you have your **credentials.json** and **eas.json** files configured [as described above](#credentialsjson). 195 196Developers tend to provide CI jobs with secrets by using environment variables. One of the challenges with this approach is that the **credentials.json** file contains a JSON object and it might be difficult to escape it properly, so you could assign it to an environment variable. One possible solution to this problem is to convert the file to a base64-encoded string, set an environment variable to that value, and later decode it and restore the file on the CI. 197 198Consider the following steps: 199 200- Run the following command in the console to generate Base64 string based on your credentials file: 201 <Terminal cmd={['$ base64 credentials.json']} /> 202- On your CI, set the `CREDENTIALS_JSON_BASE64` environment variable with the output of the above command. 203- In the CI job, restore the file using a simple shell command: 204 <Terminal cmd={['$ echo $CREDENTIALS_JSON_BASE64 | base64 -d > credentials.json']} /> 205 206Similarly, you can encode your keystore, provisioning profile and distribution certificate so you can restore them later on the CI. To successfully trigger your build using local credentials from CI, you'll have to make sure all the credentials exist in the CI instance's file system (at the same locations as defined in **credentials.json**). 207 208Once the restoring steps are in place, you can use the same process described in the [Triggering builds from CI](/build/building-on-ci.mdx) guide to trigger the builds. 209