Server verification
Why Play Integrity and App Attest must be checked on your backend, and how Rampart fits in.
On-device checks run on hardware the attacker may control. Google and Apple offer signals that are signed by their own infrastructure or by the device's secure hardware, so your server can verify them:
| Platform | Service | What your server learns |
|---|---|---|
| Android | Play Integrity API | The request comes from your genuine app, installed from Google Play, on a device that passes integrity checks. |
| Android | Key attestation | Hardware-backed proof of verified-boot and bootloader-lock state. |
| iOS | App Attest | The request comes from a genuine instance of your app on a real Apple device. |
| iOS | StoreKit AppTransaction | The app was obtained from the App Store. |
The flow
- The app asks your backend for a nonce (single use, short-lived).
- The app runs
Rampart.runChecks()and computesRampart.reportDigest(report, nonce). - The app requests a Play Integrity token or an App Attest assertion bound to that digest.
- The app sends the sensitive request, the token and the report to your backend.
- Your backend verifies the token with Google, or the App Attest data against Apple's root certificate.
- Your backend checks the nonce, the digest, the verdicts and freshness, then allows, steps up or denies.
Rampart itself makes no network calls: token generation uses the platform APIs (for example via
@expo/app-integrity), and only your backend talks to Google or Apple.
What binding does and does not do
reportDigest(report, nonce) lets you put a hash of Rampart's report inside the attested request.
That stops replaying an old token or editing the report in transit. It does not stop a fully
compromised device from lying about its own report before it is hashed — which is exactly why the
server decision must lean on the vendor verdicts.
A rampart-server package with verification helpers is planned.