Skip to Content
App AttestationRolling out: monitor to enforce

Rolling out: monitor to enforce

For the console admin and the backend developer together. At the end of this page, your API refuses unattested requests on the endpoints you chose, based on measurements rather than guesses, and you know when each policy change reaches devices.

Before you start

1. Monitor

In monitor mode the verifier issues a token even when a policy check fails, recording tp.result fail and the reasons in tp.reasons. Your API logs the result and allows every request.

Two outcomes are refused in both modes: an app the policy doesn’t list gets 403 app_not_allowed, and forged evidence never yields a token.

A key certificate whose attestation failed lives one Access token lifetime, so devices that fail are judged again at each refresh, under the policy current at that time.

2. Measure

Measure per endpoint, over a period that covers your release cycle:

  • the share of requests without the header. They come from app versions without attestation, devices that can’t attest, attestation failures, and requests that went out while the app was still waiting for a token;
  • fail results, by reason code in tp.reasons, by platform (tp.plat) and by app (tp.app).

3. Adjust the policy

Use the reasons to decide what the policy should accept. For example, dev_environment shows Xcode-run builds, security_level_insufficient or verified_boot_failed show Android devices below the chosen bar, and Play Integrity reasons show which verdicts devices fall short of. Change the settings on the Policy tab, then Sign and publish. The changes reach devices as described in When changes take effect.

4. Enforce

  1. Turn off Accept development builds and Allow debug tokens, and remove TRUSTPIN_DEBUG_TOKEN_HASHES from production verifiers.
  2. Switch Mode to Enforce, and Sign and publish. From then on, a device whose attestation fails gets no token.
  3. In the API, refuse requests without a valid token, the most sensitive endpoints first, one at a time.

Tokens issued before the switch keep tp.result fail until they expire, up to one Access token lifetime; the verifier can’t recall them. For an immediate cut-off, the API rejects tp.result == "fail" itself.

If you check tokens at a gateway, the gateway recipes refuse a request without the header, or with any failed check, whatever the policy’s mode. During monitor, check tokens in the API instead, or adapt the recipe to log and let the request through.

5. Keep a fallback

Requests without the header never stop arriving entirely: old app versions, devices that can’t attest, and attestation failures. The SDKs never block a request themselves, so your API decides, per endpoint: refuse sensitive operations, rate-limit harder, or flag the session.

When changes take effect

A new policy version first reaches each verifier within its refresh interval, 5 minutes by default. The table counts from then.

ChangeTakes effect on devices
Removing an app or a signing digest, turning off Accept development builds, switching monitor to enforceAt each device’s next token refresh, so within one Access token lifetime. The refresh answers invalid_key_certificate, and the device attests again under the new policy
Tightening a device check: security level, verified boot, bootloader, patch level, Play Integrity verdictsAt each device’s next attestation only, so within one Key certificate lifetime (30 days by default)
Turning on Require token bindingAt the next attestation or refresh: one without a binding is refused with 400 binding_required
Access token lifetime or Key certificate lifetimeTokens and key certificates issued from then on; existing ones keep their expiry
Listing an app again, or relaxing a checkAt the device’s next attempt. A device the verifier refused waits the time the verifier set, TRUSTPIN_REFUSAL_RETRY_AFTER (10 minutes by default), before trying again

Troubleshooting

SymptomLikely causeFix
Requests are refused while the policy is in monitor modeA gateway recipe enforces whatever the modeCheck tokens in the API during monitor, or make the recipe log and pass
tp.result fail still appears after switching to enforceTokens issued before the switchWait one Access token lifetime, or reject fail in the API
A tightened device check doesn’t show upDevice checks apply at the next attestationExpect it within one Key certificate lifetime

Next steps