Vouch
Security

Attestation

How a device proves itself, what each verdict means, and why a device that cannot attest is never failed.

Attestation asks the platform to vouch for the device and the build. Android uses Play Integrity and iOS uses App Attest.

A device that cannot produce either, an older iPhone, a handset with no Play services, a de-Googled Android, is reported as degraded with a reason rather than failed, and your policy decides what that is worth.

The exchange

Ask for a nonce

POST /v1/sdk/attest/nonce

Returns a single-use nonce and its expiry. It binds the platform's answer to this one attempt, so a captured attestation cannot be presented again later.

Get the platform's answer

The SDK passes the nonce to Play Integrity or App Attest and receives a signed token.

Exchange it

POST /v1/sdk/attest

Vouch verifies the token against Apple or Google, records a verdict, and returns a run token.

The response looks like this:

{
  "verdict": "pass",
  "reasons": [{ "code": "debug_device", "message": "Registered development device, attestation skipped." }],
  "source": "debug",
  "run_token": "…",
  "expires_at": "2026-09-17T11:18:57Z",
  "from_cache": false,
  "debug": true
}

Results are cached per device for a configurable window, so a busy app stays inside the platform quotas rather than attesting on every launch.

Verdicts

VerdictMeaning
passGenuine app, genuine device, official install.
degradedVouch could not fully establish the device. Not a failure.
failThe platform says the app or device is tampered, emulated or unofficial.

Every verdict carries reasons, each with a machine code and a sentence. Common ones:

CodeMeans
verifier_not_configuredNo Play Integrity credentials are set, so Android cannot be checked.
no_play_servicesThe handset has no Google Play services.
platform_unavailableApple or Google could not be reached.
app_not_recognisedThe installed binary is not the one you published.
app_unofficial_installInstalled from somewhere other than the official store.
device_not_trustedThe platform does not trust the device.
device_emulatorThe platform reports an emulator.
nonce_mismatchThe attestation does not match the nonce it was issued for.
assertion_counter_replayAn App Attest assertion was replayed.

Signals the SDK notices itself are reported as categories, never raw device data: signal_rooted, signal_debugger, signal_hooking, signal_repackaged, signal_emulator and signal_unofficial_installer.

Why degraded is never failed

If you take one thing from this page: a degraded device is usually a customer, not an attacker. De-Googled handsets, older systems and unreachable platform APIs all produce degraded. Treat it as a policy decision, not a verdict.

The verifier will not refuse a degraded device on your behalf. Your policies decide, and monitor mode tells you how many real people that decision would affect first.

Run tokens

A successful attestation returns a run token, once. Only its hash is stored.

PropertyValue
Bound toDevice, app, app version and platform
Default lifetime15 minutes
Maximum lifetime24 hours

Revoking a device's tokens ends its access immediately:

curl -X POST https://api.vouch.dev/v1/apps/app_123/security/devices/dev_abc/revoke \
  -H "Authorization: Bearer sk_live_…"

Development devices

You cannot attest properly from a simulator, so register the handsets you develop on.

curl -X POST https://api.vouch.dev/v1/apps/app_123/security/debug-devices \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"device_id":"dev_abc"}'

A registered device gets a pass labelled debug, and only with a test key. A live key refuses debug attestation outright, so the list can never become a way into production.

Credentials you need

VariableIf unset
VOUCH_PLAY_INTEGRITY_CREDENTIALSA Google service-account JSON, as a path or contents, for a project with the Play Integrity API enabled. Without it every Android device is degraded with reason verifier_not_configured, and nothing fails.
VOUCH_APP_ATTEST_ENVproduction or development, choosing which App Attest environment to expect. App Attest needs no credentials: it verifies against Apple's pinned root.

On this page