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