The problem
You can't trust the client. Your app talks to your server over the internet, and anyone can point a script at that same server and pretend to be your app. They can replay someone's credentials, call your endpoints directly, automate behavior your UI was never designed for, and otherwise act like a real user while being nothing of the sort. The numbers you see in your dashboard start lying to you, and the decisions you make off those numbers go wrong in quiet ways.
So how do you know a request came from your real, unmodified app on a real device? You need something software alone can't manufacture. That's what hardware attestation gives you: the device's own hardware vouching for the request.
What attestation is
When your app wants to prove it's genuine, your server sends it a short-lived challenge, basically a random number that expires in seconds. The device's secure hardware signs that challenge with a private key that physically never leaves the chip. Your server takes the resulting signature, called a token, and hands it to the platform (Apple or Google). The platform confirms: yes, this was signed by real hardware, running a real copy of this specific app, and the challenge matches the one you sent.
Think of it like a notarized letter, except the notary is a chip inside the phone. The letter says "I am the real app, on real hardware," and nobody can forge it because forging it would require the key, and the key never comes out of the chip. You can read the letter. You can copy the letter. The signature still only works once, for the challenge it answered.
The Secure Enclave
On Apple devices, the chip doing this signing is called the Secure Enclave. It's a separate processor physically isolated from the main CPU. It stores cryptographic keys, runs its own tiny firmware, and does signing operations inside itself. No software running on the main processor can read those keys. Not your app, not the operating system, not Apple. The Secure Enclave only ever hands back the output of a signing operation, which is the signature itself, never the key that produced it.
This is what makes attestation meaningful. If the key lived in regular memory, an attacker with enough access could extract it and sign their own tokens. The Secure Enclave makes that physically impossible with current technology. The key is the device, in a way that can't be separated from it.
The platform services
Apple and Google each offer their own service that wraps this hardware capability and gives your server something it can verify. They differ in detail but all answer the same question: did this request come from genuine hardware running a genuine copy of this app?
- App Attest is Apple's current, fully hardware-backed service for iOS. It uses the Secure Enclave directly and is what Apple recommends for new apps.
- DeviceCheck is an older Apple service. It can confirm device authenticity and also lets you store two persistent bits of state per device on Apple's servers, useful for things like tracking whether a device has ever been flagged, without storing anything yourself.
- Play Integrity is Google's current Android equivalent. It checks the device, the app, and the environment all in one verdict.
- SafetyNet is the older Google service that Play Integrity replaced. You'll still see it mentioned in older documentation and in codebases that haven't migrated yet.
Our posts in the series name all four because we looked at all of them before settling on our approach. App Attest and Play Integrity are the ones to reach for today.
What it can't do
Attestation is a high bar, and it's worth being honest that it isn't a guarantee.
A determined attacker who owns a real device with a real signed copy of your app can still cause trouble. They can route requests through a proxy so one attested session covers many fabricated ones. They can write automation that talks to their real app and records its traffic. They can find ways to extract attestation tokens and replay them within the window they're valid. None of those are easy, but a well-funded, motivated adversary willing to do the work can get around attestation.
What attestation prices out is casual and scripted abuse: the bots that point a script at your API with no device at all, the farming operations that spin up fake accounts by the thousand, the crawlers that call your endpoints from a laptop. Those represent the vast majority of the abuse that distorts your numbers and warps your features. Attestation stops nearly all of it. It's not a substitute for thinking carefully about rate limits, trust scores, and human review on the other side, but it removes the low-effort floor of the problem so you can focus on what's left.
How we use it
Rather than talking directly to App Attest, Play Integrity, and DeviceCheck ourselves, we use Firebase App Check, which wraps all three and hands our backend a single verified token. The token includes a provider field that names which underlying service vouched for the request, so we can see whether it came from a device running App Attest, DeviceCheck, or Play Integrity.
That attestation result is one of the inputs that feeds into the per-user trust score we maintain for every account. A device that passes attestation has cleared one more bar, and that clears space for it to earn more trust over time. A request that can't produce a valid App Check token doesn't get very far.
The mechanics of how App Check tokens flow through our backend, including how we handle debug tokens in development without weakening production, are covered in the App Check post. How the attestation result feeds into the trust score, and what the trust score does from there, is in the Trust Is a Budget post.