android:<hash>) and mints a short-lived
client token for it. The only credential your app ships is a publishable
key, which is mint-only.
How the flow works
Device auth is a three-step handshake against publishable-key-only routes:POST /v1/device/android/challenge— the gateway issues a single-use challenge (valid ~5 minutes).POST /v1/device/android/attest— on first launch, the app returns a Play Integrity classic verdict bound to the challenge, plus a hardware-backed Android Keystore EC public key that becomes the device’s durable identity. The gateway decrypts and verifies the verdict against your project’s response keys, stores the device’s public key, and mints a token for the per-device end user.POST /v1/device/android/assert— a returning device proves liveness with a Keystore signature over a fresh challenge, and mints again — no Play Integrity call, keeping the verdict quota off the hot path.
authentication_error, so a probe learns
nothing about which check failed. The abuse bound lives on challenge issuance, covered by the same
per-key and per-IP mint limiter as the backend mint route.
1. Link a Google Cloud project and enable Play Integrity
In the Google Play Console and Google Cloud console:- Link the app to a Google Cloud project. In Play Console, open your app → Play Integrity API (App integrity), and link it to a Cloud project (or a self-linked Cloud project). Record that project’s numeric Cloud project number — you’ll enter it in the dashboard and pass it to the SDK.
- Enable the Play Integrity API in that Cloud project (Google Cloud console → APIs & Services → enable Play Integrity API).
2. Get the verdict response keys
Roadie verifies each verdict with your project’s response keys. Choose one of two modes:- Local decryption (recommended). Roadie decrypts and verifies the verdict in-process with your Play Console response keys — no outbound network on the auth path. In Play Console → App integrity → Response encryption, download the base64 AES decryption key and the base64 EC verification key. You’ll upload both to Roadie.
- Google-managed. Roadie calls Google to decode each verdict. Create a service account with the Play Integrity role in the Cloud project and download its JSON. You’ll upload the JSON to Roadie.
3. Record the app identity
Roadie pins each verdict to your app’s public identity:- Package name — your app’s
applicationId, reverse-DNS (e.g.com.faridrahmani.CreatePro). - Signing-certificate SHA-256 digest(s) — from Play Console → App integrity (Play App Signing). Copy the SHA-256 of the app signing certificate; you may list more than one (e.g. an upload key plus the Play-managed signing key).
4. Configure the project in the dashboard
Open Project → Device attestation (Android) in the dashboard and fill in the Play Integrity config:
Then upload the Play Integrity keys. The key material is write-only — it is encrypted on upload and
never shown again. Which materials the dashboard asks for is driven by the config:
- Local mode — the AES response-decryption key (base64) and the EC verification key (base64 or PEM).
- Google-managed mode — a service-account JSON.
- Local mode with the free-tier guard on — the AES + EC keys and a service-account JSON (the service account is what Device Recall’s read/write API needs, even when verdicts are decrypted locally).
Device Recall: reinstall-proof free tier
Device Recall is Roadie’s durable, reinstall-proof free-tier guard — the Android analog of iOS DeviceCheck. Google persists a per-device signal that survives app reinstalls and device erase, so a device cannot farm a fresh free tier by reinstalling. When a device that has already burned its monthly free allotment re-attests, the guard stamps the reservedfree_exhausted tier, which
paywalls it until the UTC month rolls over — or until you grant it pro.
- Fail-open. An older SDK, an unsupported device, or a Device Recall API error simply grants the normal free tier and never blocks the mint.
- Requires Google enrollment. Device Recall is a gated Play Integrity feature — request enrollment with Google early, before you rely on it.
- Requires a service account. The Device Recall read/write API needs a Google service-account JSON (uploaded with your keys above), even in local verdict-decryption mode.
- Toggle. The Free-tier guard checkbox on the config page is the per-project on/off.
PlayIntegrityTokenProvider re-attests periodically (default every 12 hours, tunable via
PlayIntegrityOptions.attestRefreshInterval) so the durable “free consumed” bit is refreshed within
that window. Calling refreshAttestation() — for example when you present a paywall — forces an
immediate attest so the bit is written now. This is the bridge to
Free → Pro with entitlements.
Wire up the SDK
The Roadie Android SDK ships aPlayIntegrityTokenProvider that performs the
whole handshake for you — generate/attest the Keystore key on first run, assert on later runs, cache
the token in memory, and re-mint before expiry or after a 401. Apps distributed outside Google
Play (or via an SDK) must pass the Cloud project number; Play-distributed apps may omit it.
Play Integrity requires a real device with Google Play Services — it does not run on bare emulators or
CI. The SDK puts Play Integrity and the Keystore behind interfaces so JVM tests inject fakes.
What you get
- Short-lived, per-device client tokens with no secret shipped in the app.
- Each device is a distinct end user, so per-user limits and blocking apply per device.
- A clean upgrade path from an anonymous free device to a paying customer via entitlements — made reinstall-proof by Device Recall.
Related
Android SDK reference
The full chat, embeddings, image, and token-provider API.
Mobile device auth
The device-auth concept and the iOS App Attest setup.
Client tokens
How device attestation mints a token.
Free → Pro entitlements
Turn a free device into a paying user.