React Native Code Signing: Certificates and Provisioning Profiles
AI generated
RN
native
React Native · Expo · iOS · Android · Distribution
Code Signing: Certificates and Provisioning Profiles
how iOS and Android apps actually become trustworthy

Code signing decides whether a React Native app can even be installed on a test device, let alone published to the App Store or Play Store. Anyone who does not understand how a certificate, a provisioning profile, an app ID and a team fit together loses hours to cryptic build errors. This guide explains the full signing system for iOS and Android and shows how EAS Credentials and Fastlane match replace most of the manual effort.

18 min read Code Signing · Provisioning Profiles · EAS Credentials · Fastlane match React Native · Expo SDK 51+ · iOS · Android

1. Why code signing is unavoidable for React Native apps

Code signing is the mechanism iOS and Android use to cryptographically verify that an app really comes from the claimed developer identity and has not been tampered with since it was signed. For React Native apps nothing changes about this principle compared to a purely native app: the JavaScript bundle is built by Metro, but the end result is still a native iOS or Android package subject to exactly the same signing rules as an app written in Swift or Kotlin. Anyone who treats code signing as an afterthought will trip over cryptic error messages at the very latest during the first TestFlight upload or the first Play Store submission.

The difference between iOS and Android is fundamental, though. Apple requires a centrally managed system of certificates, app IDs and provisioning profiles controlled through the Apple Developer account. Android, by contrast, is built around a self-generated keystore that the developer is responsible for safeguarding. Both systems pursue the same goal: making sure updates to an app can only ever come from the same identity as the initial installation. The following sections explain both systems in detail and show how tools like EAS and Fastlane now automate most of the manual code signing work.

2. Apple's certificate system: certificates, CSRs and team ID

At the center of iOS code signing sits the certificate. It is requested via a Certificate Signing Request (CSR) based on a private key generated locally in the Keychain (macOS) or encrypted in a credentials store (EAS). Apple signs this CSR and issues a public certificate bound to that private key. There are Development certificates for development builds and Distribution certificates for release builds, and both types are tied to a Team ID that uniquely identifies the Apple Developer account.

A common misconception: the certificate alone is not enough to install an app on a device or submit it to the App Store. It is only half of the code signing process; the other half is the provisioning profile, explained in the next section. It is also worth noting: if the private key belonging to a certificate is lost, for example due to a machine change without a Keychain export, an entirely new certificate must be created and re-linked in every affected provisioning profile.


# Generate a Certificate Signing Request locally (manual workflow)
# 1. Open Keychain Access -> Certificate Assistant -> Request a Certificate
# 2. Save the .certSigningRequest file, upload it in the Apple Developer portal
# 3. Download the resulting .cer file and double-click to install it

# Equivalent, fully automated via EAS credentials manager
eas credentials
# Select platform: iOS
# Select: Build Credentials -> Set up a new Distribution Certificate
# EAS generates the CSR, uploads it to Apple, stores the private key encrypted

3. Provisioning profiles: binding app ID, devices and certificate

A provisioning profile is the file that ties three elements together into a valid signing configuration: the app ID (the app's bundle identifier), one or more certificates, and, for Development and Ad Hoc profiles, a list of registered test devices identified by their UDID. Without a matching provisioning profile, iOS refuses to install an app even if the certificate itself is valid. For code signing in production environments there are three relevant profile types: App Store profiles for release, Ad Hoc profiles for testing on registered devices outside TestFlight, and Enterprise profiles for internal distribution outside the App Store.

Provisioning profiles expire, typically after one year, and must be renewed. In practice this leads to one of the most common code signing problems: an app that has built without issue for months suddenly fails because the profile quietly expired in the background. Xcode renews expired profiles automatically for manual signing when "Automatically manage signing" is enabled; for CI pipelines and EAS builds, the respective credentials management handles this instead, which is why it pays to check profile expiry dates ahead of larger releases.


{
  "build": {
    "production": {
      "ios": {
        "credentialsSource": "remote",
        "distribution": "store"
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "developer@example.com",
        "ascAppId": "1234567890"
      }
    }
  }
}

4. Android keystores and signing configs

Android forgoes a centralized certificate system like Apple's and instead relies on a self-generated keystore. A keystore is a file that holds a private key and a self-signed certificate used to sign every APK or AAB. For code signing on Android the rule is: the keystore used to publish the very first version of an app to the Play Store must be reused for every future update. Google checks on every upload whether the signature matches the original certificate. If the keystore is lost, the existing app identity in the Play Store can no longer be updated without Google's help.

Since the introduction of Play App Signing this risk has been mitigated: developers upload their apps signed with an upload key, and Google internally signs the final package with a separate app signing key kept securely on Google's side. If the upload key is lost, a new one can be registered through Play Console support without losing the app's identity. For React Native projects built with Expo, EAS handles this entire process, including keystore generation and storage, which makes manually handling `.jks` files unnecessary for most teams.


# Generate an Android keystore manually (only needed for non-EAS workflows)
keytool -genkeypair -v \
  -keystore release.keystore \
  -alias upload \
  -keyalg RSA -keysize 2048 -validity 10000

# Inspect an existing keystore's fingerprint (SHA-256), useful for
# verifying it matches the one registered in Play App Signing
keytool -list -v -keystore release.keystore -alias upload

5. EAS Credentials: letting a tool manage code signing

The EAS Credentials manager (`eas credentials`) is, for most React Native and Expo teams today, the most pragmatic way to handle code signing. For iOS it can automatically generate certificates and provisioning profiles, register test devices for Ad Hoc builds, and store private keys encrypted within Expo's infrastructure. For Android it generates keystores or imports existing ones and links them directly to the relevant build profile in `eas.json`. The big advantage: developers no longer need to click through the Apple Developer portal manually to renew an expired profile.

Even so, code signing via EAS is not a black box. Running `eas credentials` at any time shows exactly which certificate, profile, and keystore are currently active for a given build profile, and existing credentials can be exported if a team later switches to a different CI setup. For teams running multiple apps or app variants (say, staging and production as separate bundle IDs), it is worth naming credentials explicitly per build profile in `eas.json` so a staging certificate never accidentally ends up in a production build.

6. Fastlane match: syncing certificates across a team

Fastlane `match` takes a different approach from EAS Credentials: it stores certificates, private keys and provisioning profiles encrypted in a private git repository (or alternatively a cloud storage bucket) and synchronizes them via a shared passphrase across every team member and CI runner. For teams that run their own CI pipeline, say with GitHub Actions or GitLab CI instead of EAS Build, `match` is the established solution for keeping code signing reproducible without every developer generating their own local certificates.

The key advantage of `match` over individually generated per-developer certificates: there is exactly one set of credentials per environment (Development, Ad Hoc, App Store) shared by everyone. That drastically reduces the number of active certificates in the Apple Developer account, which matters since Apple caps the number of simultaneously valid distribution certificates at three anyway. The downside: the match repository itself becomes a critical asset that needs careful protection, and its passphrase must never end up in plain text inside a pipeline configuration.


// Fastfile: sync iOS signing credentials from the match repository
// before building, so CI never generates its own certificates
platform :ios do
  lane :beta do
    match(
      type: "appstore",
      readonly: is_ci,
      app_identifier: "com.example.myapp"
    )
    build_app(scheme: "MyApp", export_method: "app-store")
    upload_to_testflight
  end
end

7. Manual signing in Xcode: when it still makes sense

Despite EAS and Fastlane, manual code signing directly in Xcode remains relevant for some scenarios, such as debugging native modules that require their own Xcode workspace, or small teams without any CI infrastructure. Xcode offers two modes for this: "Automatically manage signing", where Xcode generates and renews certificates and profiles on its own using the signed-in Apple account, and manual signing, where developers explicitly pick a specific provisioning profile and certificate.

Automatic signing is convenient for a single developer, but quickly becomes messy in teams because each developer may generate their own development certificates that overwrite one another. For projects that also work with EAS or Fastlane in parallel, it is therefore worth enabling manual signing in Xcode and explicitly referencing the same profiles the CI pipeline uses, so that code signing stays consistent between local development and automated builds instead of running two parallel, conflicting certificate systems.

8. Common signing errors and how to fix them

The most common code signing error reads roughly "No signing certificate found" or "Provisioning profile doesn't match the entitlements file". In most cases one of three causes is behind it: the provisioning profile has expired, the app ID in the profile does not match the bundle identifier in the Xcode project, or the app's entitlements (such as Push Notifications or App Groups) are not enabled in the profile. A look at the Apple Developer account, under Certificates, Identifiers & Profiles, usually reveals immediately which of the three issues applies.

A second common error involves the team ID: when a project switches between multiple Apple Developer accounts, for example from a personal to a company account, stale team ID references often remain in the Xcode project file. Code signing then fails even though every certificate in the new account is valid. The third classic case is an expired push certificate, which is managed separately from the app certificate and is easy to overlook if push notifications were only added to the app later.


// build.gradle (app module): signing config referencing a keystore
// via environment variables, so the keystore itself never lives in git
android {
    signingConfigs {
        release {
            storeFile file(System.getenv("ANDROID_KEYSTORE_PATH") ?: "release.keystore")
            storePassword System.getenv("ANDROID_KEYSTORE_PASSWORD")
            keyAlias System.getenv("ANDROID_KEY_ALIAS")
            keyPassword System.getenv("ANDROID_KEY_PASSWORD")
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

9. Comparison: manual signing, Fastlane match and EAS Credentials

Choosing the right code signing strategy depends heavily on team size, CI infrastructure, and whether a project relies on Expo/EAS or a custom build pipeline. The following overview compares the three most common approaches along the criteria that matter most in practice.

Criterion Manual Xcode signing Fastlane match EAS Credentials
Team synchronization None, per developer Git repository, shared passphrase Centralized via Expo account
Requires own CI pipeline Yes, mostly local Yes (GitHub Actions, GitLab CI, Jenkins) No, EAS Build handles this
Setup effort Low, but error-prone in teams Medium, requires repository setup Low, one command
Control over raw material Full, everything local in Keychain Full, own repository Limited, encrypted at Expo
Recommendation Solo developers, native debugging sessions Teams with their own CI, without Expo Expo/EAS projects, small to mid-size teams

For most new React Native projects that already rely on Expo and EAS Build, EAS Credentials is the lowest-maintenance path for code signing. Teams that must run their own CI infrastructure for regulatory or historical reasons will find Fastlane match more reliable, since it keeps full control over the credentials repository. Manual signing in Xcode remains a useful complement for local development, but it should not be the primary strategy for production releases.

Mironsoft

React Native development, app distribution and store release

Code signing without stress at every release?

We set up EAS Credentials or Fastlane match once, properly, document certificate management for your team, and make sure provisioning profiles get renewed before they expire.

Signing setup

Set up and document EAS Credentials or Fastlane match from scratch

Migration

Move existing manual signing workflows into automated pipelines

CI integration

Make signing reliable and reproducible in GitHub Actions or EAS Build

10. Summary

Code signing for React Native apps follows clearly structured, if different, rules on iOS and Android. On iOS, the certificate, the app ID and the provisioning profile together form the valid signing configuration; if any one of the three is missing or expired, the build fails. On Android, a self-generated keystore takes on this role, backed by Play App Signing, which keeps the critical app signing key safely on Google's side. EAS Credentials automates both systems almost entirely for Expo projects, while Fastlane match remains the established alternative for teams running their own CI infrastructure.

The biggest lever against recurring signing problems is settling on a single, documented strategy early on, rather than running manual Xcode signing, EAS Credentials and Fastlane match in parallel and uncoordinated within the same project. Anyone who treats code signing as a fixed part of the release pipeline and keeps an active eye on certificate and provisioning profile expiry dates avoids most short-notice build failures ahead of important releases.

Code signing for React Native, the essentials at a glance

iOS signing

Certificate, app ID and provisioning profile must all match. Check each element separately when a build fails.

Android signing

Never lose the keystore. Play App Signing separates the upload key and the app signing key, making recovery possible.

Automation

EAS Credentials for Expo projects, Fastlane match for custom CI pipelines, both replace error-prone manual signing.

Maintenance

Actively monitor certificate and profile expiry dates, expired credentials are the most common cause of build failures.

11. FAQ: Code Signing for React Native Apps

1Certificate vs. provisioning profile?
The certificate proves identity, the profile links it to app ID and devices. Both together form valid code signing.
2How long do provisioning profiles last?
Typically one year, then they need renewal, automatically via Xcode/EAS or manually in the Developer portal.
3Lost the Android keystore, what now?
Without Play App Signing an update is nearly impossible. With it, Google support can register a new upload key.
4EAS Credentials or Fastlane match?
EAS for Expo projects, match for teams with their own CI pipeline and more control needs over the credentials repository.
5Cause of "No signing certificate found"?
Usually a missing valid certificate in the Keychain or an expired profile. Check the Developer portal.
6How many distribution certificates does Apple allow?
Maximum three active per team. match reduces the need through credentials shared across the whole team.
7Sign staging and production separately?
Yes, through separate bundle IDs and dedicated build profiles in eas.json, or separate match environments.
8What does the app signing key do in Play App Signing?
It is the final key Google uses to sign the published app. The upload key stays with the developer and can be replaced.
9Do push certificates need separate management?
Yes, they expire independently of the app certificate and are easily overlooked if push was added later.
10Can I export EAS credentials?
Yes, eas credentials lets you view and download all certificates, profiles and keystores, no vendor lock-in.