⏱️ Reading time: 12 min
Just a year ago, installing GrapheneOS meant resigning yourself to the bank showing a red “unsupported device” screen. Today several banking apps that used to block any non-factory Android let the same phone through without the user changing anything on their end. The change didn’t come from a data-spoofing app or a hack: it came from how the verification those apps use under the hood, called Play Integrity API, actually works.
📑 En este artículo
- TL;DR
- What Is Play Integrity API?
- The Three Verdict Levels of Hardware Attestation
- How the Hardware Chain of Trust Works
- Practical Examples: How a Bank’s Backend Uses It
- How GrapheneOS Manages to Pass Android’s Integrity Verification Without Relying on Google
- Common Mistakes and Gotchas
- Comparison with Alternatives
- How to Get Started: Checking the Verdict on Your Own Phone
- Going Deeper: The Certificate Extension That Makes It Possible
- Frequently Asked Questions
- Does Play Integrity API completely replace SafetyNet Attestation?
- Does GrapheneOS need to root the phone to work?
- Does any bank that accepts factory Android automatically accept GrapheneOS?
- What happens if I leave the bootloader unlocked on GrapheneOS?
- Does the Auditor app do the same thing as Play Integrity API?
- References
Understanding that verification explains why GrapheneOS can pass it legitimately, without hiding anything and without depending on Google endorsing its operating system.
TL;DR
- Play Integrity API replaces SafetyNet and classifies each device into three levels: basic, device, and strong.
- Hardware attestation depends on the phone’s security chip, not on the operating system running on top of it.
- GrapheneOS relocks the bootloader with its own key and keeps the Pixel hardware’s chain of trust intact.
- A banking app never decides on its own: it sends a token to Google’s servers and waits for a signed verdict.
- The ‘yellow’ Verified Boot state certifies a system other than the factory one without flagging it as compromised.
What Is Play Integrity API?
Play Integrity API is the Google Play service that lets an Android application ask the system whether the device, the app, and the account are genuine before performing a sensitive action. It replaces the old SafetyNet Attestation and delivers a cryptographically signed verdict, not an opinion the phone forms about itself.
Google fully retired SafetyNet Attestation and migrated the banking, delivery, and gaming ecosystems to Play Integrity API, which relies on hardware-backed cryptography instead of a list of software checks that are easy to fake. The difference is key: SafetyNet could be spoofed with modules that injected the correct responses, while Play Integrity API requires a signature that only a physical chip can produce.
Why It Matters for GrapheneOS Users
For years, much of mobile banking in Latin America and Europe rejected any Android that wasn’t “factory,” regardless of whether it passed Google’s official verification. That policy depended on each development team: some added their own checks (looking for root binaries, checking whether the bootloader was unlocked) on top of the official verdict, and rejected anything they didn’t recognize.
The GrapheneOS Mastodon account reports a growing number of cases of banks simplifying that logic and trusting the API’s verdict directly instead of maintaining their own blacklists. That opens the door to any system that passes it legitimately, GrapheneOS included, without the user having to hide anything.
💭 Key point: the API’s verdict doesn’t say “this is factory Android.” It says “the hardware is genuine and the boot is verified.” Those are two different questions, and only the second one is the one a bank actually cares about.
The Three Verdict Levels of Hardware Attestation
Play Integrity returns a field called deviceRecognitionVerdict that can include up to three cumulative labels. The more that appear in the response, the stricter the guarantee the requesting backend receives.
| Level | What It Certifies | Does GrapheneOS Reach It? |
|---|---|---|
| MEETS_BASIC_INTEGRITY | The device shows no obvious signs of being an emulator or an unconcealed root | Yes |
| MEETS_DEVICE_INTEGRITY | It’s a Google-certified model (Play Protect certified) with a valid hardware attestation key | Yes, on supported Pixels |
| MEETS_STRONG_INTEGRITY | Certified hardware plus verified boot with a locked bootloader and no recent unlocks detected | Yes, if the user relocks the bootloader after installing |
A device can receive all three levels at once because they’re cumulative: reaching the strong level automatically implies the other two. What determines the result isn’t the operating system’s brand, but the physical state of the chip and the boot at the exact moment of the query.
How the Hardware Chain of Trust Works
Every phone with a dedicated security chip (on Pixels, the Titan M2) comes with a unique attestation key burned in at the factory, signed by a certificate that traces back to the manufacturer. When an app requests a verdict, Google Play Services passes the request to that chip, which signs a declaration about the system’s state: whether verified boot is active, which key verified it, and whether the bootloader is locked.
That signature, not the operating system, is the proof of genuineness. The phone never evaluates itself: it issues a certificate that third parties can validate against the root of trust published by Google, as documented by Android Key and ID Attestation.
flowchart TD
A["Banking app"] --> B["Play Integrity SDK"]
B --> C["Google Play Services"]
C --> D["Security chip (Titan M2)"]
D --> E["Factory attestation key"]
E --> F["Signed certificate"]
F --> G["Google server verifies the chain"]
G --> H["Verdict: BASIC / DEVICE / STRONG"]
H --> I["Bank backend"]
Practical Examples: How a Bank’s Backend Uses It
The full flow involves at least three actors: the app on the phone, Google’s servers, and the bank’s own server. The app never sees the actual verdict; it only forwards an opaque token.
sequenceDiagram
participant App as Banking app
participant PS as Google Play Services
participant HW as Security chip
participant Srv as Bank server
App->>PS: requests token with nonce
PS->>HW: requests attestation signature
HW-->>PS: signed certificate
PS-->>App: opaque token
App->>Srv: sends token
Srv->>Srv: calls decodeIntegrityToken on Google
Srv-->>App: allows or blocks the operation
On the client side, the code is short. It requests a token tied to a nonce generated by the bank’s own server, to prevent anyone from reusing an old response:
val integrityManager = IntegrityManagerFactory.create(applicationContext)
val request = IntegrityTokenRequest.builder()
.setNonce(nonceDelServidor)
.build()
integrityManager.requestIntegrityToken(request)
.addOnSuccessListener { response ->
enviarAlBackend(response.token())
}
That code returns an opaque string: a JWT the client can’t read or manipulate, because only Google has the key to decode it. The real step happens on the bank’s server, which calls the API with that token:
const { google } = require('googleapis');
const playintegrity = google.playintegrity('v1');
const auth = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/playintegrity'],
});
const res = await playintegrity.v1.decodeIntegrityToken({
packageName: 'com.banco.app',
requestBody: { integrityToken: tokenDelCliente },
auth,
});
console.log(res.data.tokenPayloadExternal.deviceIntegrity);
The expected output is a JSON object with the field that defines the rest of the article:
{
"deviceRecognitionVerdict": ["MEETS_STRONG_INTEGRITY", "MEETS_DEVICE_INTEGRITY", "MEETS_BASIC_INTEGRITY"]
}
If the array includes all three levels, the bank’s backend knows it’s running on genuine Pixel hardware with a locked bootloader, regardless of which system signed that boot image.
How GrapheneOS Manages to Pass Android’s Integrity Verification Without Relying on Google
GrapheneOS doesn’t ask Google for permission or modify the security chip: it takes advantage of a feature Google already documents as part of the Android Verified Boot standard. Any compatible Pixel allows you to generate your own key and relock the bootloader with it instead of leaving it unlocked or using the factory key.
The chip keeps signing the boot state exactly as it would on a factory Pixel, except now the field identifying which key verified that signature points to the user’s key instead of Google’s. The hardware chain of trust (the one Play Integrity API actually cares about) remains intact, because it never depended on the operating system running on top, but on the chip burned in at the factory.
That’s the difference from Android rooted with tools like Magisk: there, the strategy is to hide signals (modules like Shamiko conceal root access) in a constant race against Google’s detection updates. GrapheneOS hides nothing because there’s nothing to hide: it doesn’t install system root, it publicly documents its boot state, and it passes the check because, in the exact terms Google defines, it’s a device with genuine hardware and verified boot.
stateDiagram-v2
Green: Official manufacturer key, factory Android
Yellow: User's own key, GrapheneOS case
Orange: Unlocked bootloader, no verification
Red: Invalid signature or corrupted boot
[*] --> Green
[*] --> Yellow
[*] --> Orange
[*] --> Red
Orange --> Yellow: relock with own key
Yellow --> Green: revert to factory firmware
That “yellow” state is, according to the official Android Verified Boot documentation, a legitimate verification, distinct from red (invalid signature) or orange (no locking at all). A bank that only reads the official integrity levels doesn’t distinguish between green and yellow; only those that add an extra check on the specific boot key notice the difference, and that’s a decision made by each banking team, not a limitation of the API.
Common Mistakes and Gotchas
- Confusing passing verification with unlocking everything: some banks add their own validations outside the API (device model fingerprint, geolocation, blacklists) and block GrapheneOS even when the verdict is the highest one.
- Leaving the bootloader unlocked: the state drops to orange and no banking app accepts it, with or without sandboxed Google Play installed.
- Believing the Google Play sandbox breaks attestation: that sandbox runs without system privileges, but the field the chip reads lives in the hardware, not in the Google Play package.
- Combining GrapheneOS with Magisk expecting to keep the strong level: it reintroduces exactly the root access Play Integrity API is designed to detect, and the GrapheneOS project avoids this by design.
Comparison with Alternatives
| Option | Typical Verdict | Trade-off |
|---|---|---|
| Factory Android (Pixel, Samsung) | STRONG | None, but no real control over the system |
| GrapheneOS with relocked bootloader | STRONG at most banks | Some apps add extra checks and reject it anyway |
| Custom ROM without relock, open bootloader | BASIC at most | Rejected by almost all banking apps |
| Rooted Android with Magisk and concealment | Variable and unstable | Depends on hiding signals; breaks with every Google update |
How to Get Started: Checking the Verdict on Your Own Phone
You don’t need to write code to see where your device stands. The free app Play Integrity API Checker, available on the Play Store and functional inside GrapheneOS’s sandboxed Google Play, calls the same API a bank would use.
- Install the app from the Play Store on your device.
- Open it and tap the check button.
- Read the
deviceRecognitionVerdictfield in the result.
If the bootloader was relocked correctly, the result lists all three levels: MEETS_BASIC_INTEGRITY, MEETS_DEVICE_INTEGRITY, and MEETS_STRONG_INTEGRITY. There’s no direct way to verify from the outside what each bank does with that result, because the final policy lives on its own server, not on the phone: that data isn’t public.
Anyone wanting a more technical check can use Auditor, an app that relies on the same hardware attestation mechanism but shows the full certificate to the user instead of hiding it behind a bank’s backend.
Going Deeper: The Certificate Extension That Makes It Possible
Internally, the chip doesn’t return a simple “yes” or “no.” It signs an X.509 certificate that includes a specific extension (the Key Attestation extension, identified by OID 1.3.6.1.4.1.11129.2.1.17) with a data structure that describes, among other things, whether the device is locked, the Verified Boot state, the hash of the key that verified the boot, and the installed security patch level.
The certificate chain climbs from the chip to an intermediate manufacturer key and from there to a root of trust that Google maintains and publishes. That root doesn’t change depending on the operating system: it’s a property of the hardware, burned in once at the factory. That’s why a legitimate chip keeps producing valid certificates no matter what firmware runs on top, as long as the boot stays verified against some key, official or user-owned.
Your next step: install Play Integrity API Checker on your current Android and compare the deviceRecognitionVerdict field before and after locking the bootloader with your own key.
Frequently Asked Questions
Does Play Integrity API completely replace SafetyNet Attestation?
Yes, Google retired SafetyNet Attestation and migrated developers to this new API, which is based on hardware attestation instead of software checks.
Does GrapheneOS need to root the phone to work?
No, and in fact it deliberately avoids system root: that design decision is part of why it keeps a high verdict in Play Integrity API.
Does any bank that accepts factory Android automatically accept GrapheneOS?
No. Some add their own validations (device model, geolocation) outside the official verdict, so the result varies from bank to bank.
What happens if I leave the bootloader unlocked on GrapheneOS?
The verified boot state drops to “orange” and the highest verification level stops being available to any app, including banking ones.
Does the Auditor app do the same thing as Play Integrity API?
It uses the same hardware attestation mechanism, but shows it directly to the user instead of hiding it behind a banking app’s backend.
References
- GrapheneOS on Mastodon: original thread about banks changing their verification policy.
- GrapheneOS FAQ: the project’s official documentation on attestation and banking compatibility.
- Android Developers: Play Integrity API: official documentation of the verdict levels and the migration from SafetyNet.
- Android Open Source Project: Verified Boot: specification of the green, yellow, orange, and red states of verified boot.
- Android Developers: Key and ID Attestation: details of the certificate extension that backs hardware attestation.
📱 Enjoy this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day.
Featured image: Foto de Franck en Unsplash
Did it work for you? Got a different error? Say so below: questions get answered and help the next reader.
Leave a comment
0 Comments