Introducing Expo App Integrity: Protecting your backend from unauthorized clients
Product•React Native•Development••3 minutes read
Nishan Bende
Engineering
Secure your backend with Expo App Integrity. Verify genuine app instances using Google Play Integrity and Apple App Attest.

When building apps that connect to a backend, some features or workflows may require stronger integrity checks to protect against abuse. In these cases, it can be useful to verify that requests come from genuine instances of your app running on real devices. This helps reduce the risk of modified clients, emulators, or scripts calling your APIs directly and bypassing safeguards.
Today we’re releasing @expo/app-integrity, a library that makes it easier to integrate platform app attestation services into your Expo project. It works on both Android and iOS, using Google Play Integrity and Apple App Attest APIs to verify that your app is authentic and running in a trusted environment.
How Expo App Integrity works at a high level
- App → Platform: Ask the platform (Google Play or Apple) to check the app’s authenticity.
- App → Server: Send the result of that check to your backend.
- Server: Use the platform’s verification process to confirm the result is valid.
- Server: Decide whether to allow, limit, or block the requested action.
Android
On Android, @expo/app-integrity follows the Standard request flow of Play Integrity. Prepare a token provider once, then request integrity tokens for sensitive actions.
import * as AppIntegrity from '@expo/app-integrity';// Do this once after app launch or before a sensitive actionconst cloudProjectNumber = 'your-cloud-project-number';await AppIntegrity.prepareIntegrityTokenProvider(cloudProjectNumber);// When you need to gate a server requestconst requestHash = 'action-specific-hash';const result = await AppIntegrity.requestIntegrityCheck(requestHash);// Send `result` to your server to decrypt and verify
Server verification
Decrypt and verify the token on your backend using the steps in Google’s guide, then decide how to handle the request.
iOS
On iOS, the flow is based on App Attest. You generate a hardware-backed key pair per user per device, attest it once, and then use it to assert sensitive requests.
import * as AppIntegrity from '@expo/app-integrity';// Check support before using App Attestif (AppIntegrity.isSupported) {// 1) Create a key for this user/deviceconst keyId = await AppIntegrity.generateKey();// 2) Ask your server for a unique challenge, then attest the keyconst attestationObject = await AppIntegrity.attestKey(keyId, challengeFromServer);// Send keyId + attestationObject to your server for one-time verification// 3) For sensitive requests, sign with the attested keyconst payload = { action: 'getGameLevel', levelId: '1234', challenge: challengeFromServer };const assertion = await AppIntegrity.generateAssertion(keyId, JSON.stringify(payload));// Send assertion + payload to your server for verification}
Server verification
Use Apple’s validation steps to check both the one-time attestation and subsequent assertions.
Choosing where to check integrity
You don’t need to gate every request. It is common to require integrity signals for actions like purchasing, redeeming credits, fetching premium content, or mutating important state. Start small, observe, then expand coverage as needed.
Try it today (alpha!)
As of the SDK 54 release, @expo/app-integrity is officially in alpha and available to try: npx expo install @expo/app-integrity. We would appreciate any and all feedback and all contributions are welcome. Find us on Discord, we are happy to hear your experiences, good or bad. You can help shape the future of the library while it’s in it’s early stages. This is something we intend to continue with for a very long time so please give it a try!
And join the SDK 54 livestream if you want to see a demo or ask us questions live:



