This guide walks through the operator setup for Android anonymous device auth: the Google Play Console and Google Cloud steps, uploading the verdict keys, configuring the project in the Roadie dashboard, and turning on Device Recall for reinstall-proof free-tier protection. It is the Android analog of the iOS App Attest setup in Mobile device auth. An Android app with no backend and no user accounts can still call Roadie safely. Google Play Integrity proves that a request comes from a genuine, unmodified build of your app on a real device. The gateway turns that proof into a per-device end user (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:
  1. POST /v1/device/android/challenge — the gateway issues a single-use challenge (valid ~5 minutes).
  2. 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.
  3. 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.
Every verification failure — a bad verdict, the wrong package or certificate digest, a nonce mismatch, a reused challenge, a bad key proof — collapses to one opaque 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. In the Google Play Console and Google Cloud console:
  1. 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.
  2. 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.
Local mode is the default and keeps the auth path fully offline (App Attest parity). Use Google-managed only if you cannot manage the response keys yourself.

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).
None of these are secrets — they are your app’s public identity, and they let the gateway verify that a verdict belongs to your app.

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).
Save. Android device auth is now live for the environment.

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 reserved free_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.
The gateway reads the Device Recall signal at attest to gate the free tier and writes it at assert on quota exhaustion. Because assert never calls Play Integrity, the SDK’s 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 a PlayIntegrityTokenProvider 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.
From here your calls authenticate with the client token the provider mints — you never handle the JWT or the device handshake yourself. Swapping the token provider (for example, to a static token in tests) changes nothing at the call site.
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.

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.