Skip to Content
App AttestationSetting up apps and the policy

Setting up apps and the policy

For the console admin, often the mobile lead. At the end of this page, your apps are registered with Apple and Google, a monitor-mode policy is published on the project’s Attestation page, and the verifier’s domain is registered for pinning.

Before you start

  • A TrustPin project with pinning set up. See Project setup.
  • The project signs with a cloud key (you need its master password) or with your own key (BYOK, you need the PEM file). Projects signed with FIDO can’t use app attestation in this release.
  • Access to the Apple Developer portal for your Apple apps, and to Play Console and Google Cloud for Android apps that use Play Integrity.

Apple apps

Repeat for each app.

  1. In the Apple Developer portal, enable App Attest on the app’s App ID.
  2. In Xcode, add the App Attest capability. It adds the entitlement com.apple.developer.devicecheck.appattest-environment: development for builds run from Xcode, production for TestFlight and the App Store.
  3. Note the app’s Team ID and Bundle ID. On the console form you can drop the app’s Info.plist or a .mobileprovision file to fill them in.
  4. Decide on Accept development builds. Builds run from Xcode attest in the development environment and are refused with dev_environment unless it is on. Leave it on while developing and turn it off for production.

On macOS, check which environment a build attests in: the token’s tp.env says production or development.

Android apps

Repeat for each app.

  1. Package name, for example com.example.app.

  2. Signing certificate SHA-256 for every certificate that signs a build you accept:

    • the debug key, for builds run from Android Studio;
    • the upload key, if you install builds signed with it;
    • the Play app signing key, for installs from Google Play (Play Console, Test and release, App integrity).

    keytool prints the digest of a keystore entry:

    keytool -list -v -keystore <keystore> -alias <alias> | grep 'SHA256:'

    Paste the SHA256: value into the console as printed, or drop a certificate file (.pem, .der, .crt, .cer) onto the form.

  3. Evidence: what a device must provide.

    Console optionDevice must provideFails on
    Either (the default)Every evidence it can: Key Attestation, plus Play Integrity when the app has a Google Cloud project number. Passes when at least one passes the policyDevices without hardware-backed attestation when the app has no project number, and devices that can provide neither
    BothKey Attestation and Play IntegrityDevices missing either
    Play Integrity onlyPlay IntegrityDevices without Google Play, and apps without a project number
    Key Attestation onlyKey AttestationDevices without hardware-backed attestation, and emulators

    Key Attestation only needs no Google setup and is the simplest start. Under Either, an app configured with a project number spends one Play Integrity request on every attestation, not only as a fallback, so plan your Play Integrity quota for it.

  4. Play Integrity, only with Either, Both or Play Integrity only:

    1. Enable the Play Integrity API in a Google Cloud project.
    2. Link that project to the app in Play Console (Test and release, App integrity, Play Integrity API).
    3. Turn on, in Play Console, any optional verdict the policy uses: app access risk, Play Protect, recent device activity.
    4. Create a service account for the verifier. Its JSON key goes into the verifier’s TRUSTPIN_PLAY_INTEGRITY_CREDENTIALS; see Deploying the verifier.
    5. Enter the Cloud project number in the policy’s Google Cloud project number (a dropped google-services.json fills it in) and in the app; see Android.

    Configure the project number in the app only when the policy uses Play Integrity: with a number configured, the app contacts Google Play services from setup on, which belongs in its Data safety declaration. Builds not installed from Google Play aren’t recognized by it, so keep Require an app recognized by Google Play off while you test them.

  5. Key Attestation settings:

    • Minimum security level: TRUSTED_ENVIRONMENT or STRONG_BOX. Software keys are never accepted.
    • Require verified boot and Require a locked bootloader: on for consumer production. With Require verified boot off, devices running a custom operating system with a relocked bootloader, such as GrapheneOS, are accepted; the bootloader must still be locked. In release builds, the pinning SDK refuses emulators and non-OEM operating system images unless the app’s manifest sets cloud.trustpin.android.allowNonOemImages.
    • Minimum OS patch level (YYYYMM, optional).

The console offers presets for these settings: Production and Production and development for Apple, and Recommended, Strict and Without Google Play for Android. A preset changes the settings only, never the apps you added.

Creating and publishing the policy

  1. Open the project’s Attestation page. Before setup it shows Set up app attestation; choose Set up.

  2. Add the apps under Attest Apple apps and Attest Android apps, with the settings above.

  3. Set the rest of the policy:

    SettingStart withNotes
    ModeMonitor (recommended to start)Tokens are issued even when checks fail, so you can measure before enforcing. See Rolling out
    Access token lifetime1 h (default)Presets 15 min, 1 h, 6 h and 1 day
    Key certificate lifetime30 days (default)Presets 1, 7, 30 and 90 days. It sets how often a device attests again
    Require token bindingOff until your API checks bindWith it on, an app gets no token until it has a binding. See Verifying tokens in your API
    Allow debug tokensOn for staging onlyLets simulators and emulators attest with a debug token
  4. Finish the wizard with Create the policy, then choose Sign and publish. Cloud-key projects ask for the master password; BYOK projects sign with your key and the button reads Publish. The dialog lists what the new version makes stricter, and asks you to confirm before publishing.

Each publish raises the policy version. Running verifiers pick up the new version within their refresh interval (5 minutes by default), with no redeploy. An amber dot on the Policy tab marks changes not published yet.

Check: the Policy tab shows the version as published.

Registering the verifier’s domain

The SDKs pin their calls to the verifier, and in strict mode they refuse a host that isn’t registered. Add the verifier’s host, for example attest.example.com, as a domain of the same TrustPin project, as for any domain your app calls. See Add a domain, and sign and publish the pin configuration.

Check: the domain is listed in the project, and the published pin configuration includes it.

The other tabs

TabUse
DeploymentName each environment, give its verifier URL, and download the verifier bundle. See Deploying the verifier
Go-live guideThe Go-live checklist your organization shares, step-by-step snippets, and debug tokens
StatusLive policy, Verifier fleet and Verifier checks. The danger zone, for admins and owners, can disable or re-enable attestation, or abandon a setup that was never published

Changing the policy with the CLI

Setting up attestation and its first publish happen in the console. After that, the TrustPin CLI can export, change, sign and publish the policy, for example from CI:

StepConsoleCLI
Read the policyPolicy tabtrustpin-cli projects attestation get <organization id> <project id> --output json
Store a changeEdit the Policy tabtrustpin-cli projects attestation update <organization id> <project id> --file attestation.json
Sign and publishSign and publishtrustpin-cli projects attestation sign <organization id> <project id> (add -k key.pem for BYOK)
Rehearse signingsign --dry-run
Download the verifier bundleDeployment tabtrustpin-cli projects attestation bundle <organization id> <project id> --format compose|kubernetes|env

update stores and validates the change as a new, unpublished version; only sign changes what verifiers enforce. Running update and sign with an unchanged file does nothing. In the file, each signing digest is the unpadded base64url of the SHA-256, not the colon-separated hex keytool prints. To convert one:

echo '<SHA256 value from keytool>' | tr -d ':' | xxd -r -p | base64 | tr '+/' '-_' | tr -d '='

The CLI needs a member’s personal access token: viewers can run get, config and bundle only. Disabling, re-enabling and abandoning stay in the console.

Troubleshooting

SymptomLikely causeFix
The app’s attestation fails with app_not_allowedThe Team ID and Bundle ID, or the package name and signing digest, don’t match the buildCompare them with the build that runs, including which key signed it
Builds run from Xcode fail with dev_environmentAccept development builds is offTurn it on for development, and publish
The app reports verifierUnavailable and sends no headerThe verifier’s domain isn’t registered in the projectRegister the domain
The CLI refuses to publish with “The first publish must be done in the TrustPin console.”The policy was never publishedPublish it once from the console

Next steps