App attestation asks whether a request came from your genuine, unmodified app. Device attestation asks whether the phone it runs on is genuine hardware in an expected state: a locked bootloader, a verified operating system, a hardware-backed key. Each answers a different question, and neither tells you who the user is or whether the session has been hijacked. Useful attestation combines both kinds of evidence, binds them to the request, and lets your server decide. This article covers Android and iOS, which offer different platform services and must be treated separately.
App attestation asks
- Is this my code, signed with my key?
- Has the package been repackaged or modified?
- Was it installed through an expected channel?
- Is this a genuine instance of my app?
Device attestation asks
- Is this genuine hardware?
- Is the bootloader locked and the OS verified?
- Is the key held in hardware-backed storage?
- What is the device's patch level?
Four kinds of evidence
People say “attestation” for several different claims. Separating them avoids trusting a result for something it never measured.
Application evidence
This says the code is yours: signed with your key, not repackaged, installed through an expected channel. On Android, the Play Integrity API returns an app integrity verdict that states whether Google Play recognises the package and certificate. On iOS, App Attest creates a key in the Secure Enclave and has Apple certify that the key belongs to a genuine instance of your app.
Environment evidence
This describes the running state: is the device rooted or jailbroken, is a debugger attached, is a hooking framework loaded, is it an emulator. Platform verdicts give a coarse view. In-app runtime checks see much more, but they run on the same device as the attacker, so their results must travel to the server as evidence rather than as a verdict.
Hardware evidence
This is device attestation in the strict sense. On Android, key attestation produces a certificate chain from the hardware-backed key store that describes the key and the device’s verified boot state and patch level. It proves properties of the device and the key. The certificate also names the package and signing certificate of the app that created the key, as the operating system reports them, but it says nothing about whether that app’s code was altered at runtime.
Identity evidence
Attestation does not authenticate a person. A stolen password typed into a genuine app on a genuine phone passes every check above. Account and session identity come from your login, step-up and device binding design.
- 2016
Android key attestation
Introduced with Android 7.0: a hardware-backed key store can certify its keys and the device's boot state.
- 2020
App Attest on iOS
Introduced with iOS 14: a Secure Enclave key that Apple certifies as belonging to a genuine instance of the app.
- 2021
Play Integrity API
Google announces a single API for app, device and licensing verdicts, succeeding the SafetyNet Attestation API.
Verification: freshness and the relying party
Evidence is only as good as the server that checks it. The relying party is your backend or gateway, and the app never tells the server whether it passed.
Server issues a challenge
A single-use value, or a hash of the request the app is about to send.
App collects evidence
Platform attestation plus in-app runtime evidence, bound to the challenge.
Evidence travels with the request
The app forwards it; it never computes its own verdict.
Server verifies
Signatures, challenge match, validity window, single use.
Server decides per endpoint
Allow, step up, limit or refuse, and log the result.
- Issue a challenge. Your server creates a single-use value, and the evidence must include it or a hash of the request.
- Check it where the attacker cannot. Verification runs on your side, never in the app.
- Limit its life. Evidence carries a short validity window and is accepted once, across every backend instance.
- Decide per endpoint. A balance read and a payee change deserve different thresholds and different failure responses.
- Log the failures. Rejected evidence, replays and emulator signals are the early warning your fraud team needs.
Choosing what to rely on
| Evidence source | Shows | Leaves unknown | Depends on |
|---|---|---|---|
| Play Integrity (Android) | App recognised by Google Play; device verdict tier | Runtime hooking after the check; the user | Google Play services and Google’s servers |
| App Attest (iOS) | Key belongs to a genuine instance of your app on Apple hardware | Jailbreak state; runtime tampering; the user | Apple’s servers and supported devices |
| Android key attestation | Hardware-backed key; boot, lock and patch state; the package that created the key | Runtime tampering inside the app; the user | A hardware-backed key store on the device |
| In-app runtime checks | Reports hooking, debugging, emulators, root or jailbreak and code changes, as evidence for the server | The user | Protection built into your release |
| Login and step-up | Who is acting | Whether app or device is genuine | Your identity design |
Read the “Leaves unknown” column first. Every row has a gap, and the user appears in all but the last. That is why sound designs combine sources rather than pick one.
Operational boundaries
Platform services have availability and quota limits, they need network access, and they do not exist on every device. Some markets use phones without Google Play services. Plan a fallback tier, test the failure path in observe mode before enforcing, and keep one verification contract for both platforms so your backend team does not maintain two logic trees.
Before you enforce
- List the endpoints that need evidence, and the failure response for each.
- Confirm every piece of evidence is bound to a server challenge or a request hash.
- Reject reused evidence across all backend instances, not only the one that saw it first.
- Decide the trust tier for devices without Google Play services.
- Run in observe mode and review the failure rate before switching to enforcement.
How Otukan brings the evidence together
Otukan gives your backend fresh, request-bound evidence that keeps app authenticity, device environment and request freshness as separate results. It works alongside Play Integrity on Android and App Attest on iOS, and labels which evidence came from the platform and which from Otukan’s own runtime checks for root, jailbreak, hooking, debugging and emulators.
Flutter and React Native apps are protected too, scoped per platform. The product control is covered on mobile app attestation.