Deze vertaling is machinaal gegenereerd en wacht op beoordeling.Overschakelen naar Engels
Op deze pagina

Device and app attestation

Attestation gives your backend an integrity signal from the device or app that sent a request. A workspace admin registers the mobile apps in Backoffice. Your backend then calls two Noxtica routes to verify what the device reports. Backoffice shows the results.

What it is

Availability: Availability depends on your plan, role and the modules enabled for your organisation.

There are two attestation families. They share one Backoffice page for reading results.

FamilyWhat it checksWhere you work
Mobile app attestationAndroid Play Integrity and iOS App Attest results for apps you registeredBackoffice → Integrations & API → Attestation Apps, plus POST /v1/attest/android and POST /v1/attest/ios from your backend
Hardware Attestation (web)The spread of CPU and GPU proof-of-work levels across your visitors, and server-verified GPU verdictsBackoffice → Device Intelligence → Hardware Attestation

An attestation result is a signal. Treat a missing result as unknown, not as hostile. You decide what your app does with each result.

How the mobile flow works:

  1. Your backend asks Noxtica for a single-use nonce.
  2. The app asks Google (Android) or Apple (iOS) for a token bound to that nonce.
  3. Your backend sends the token and the nonce back to Noxtica.
  4. Noxtica redeems the nonce once, checks the token, records the outcome and returns a verdict and a verification level.

The mobile SDKs for Android and iOS exist for the device side of this flow. They are private. Ask your account team for access. Do not look for them in a public package registry.

Verdict and verification level

Every mobile response carries two values. Read both.

ValueMeaning
verdict: "pass"The attestation was fully verified and the platform policy was met.
verdict: "fail"The token was not proven, was replayed, or the platform policy was not met.
verdict: "error"Noxtica could not record the result. Retry with a new nonce.
verificationLevel: "verified"The token was cryptographically proven.
verificationLevel: "structure_only"iOS only. The attestation parsed and its challenge matched, but the certificate check did not complete.
verificationLevel: "unverified"Nothing could be proven. The row is still stored.

pass is returned only with verified. A structure_only or unverified result is never upgraded to pass. Handle any other verdict value as not-pass.

Prerequisites

  • A Backoffice user with the admin role. Registering or revoking an app also needs a step-up MFA check from the last 6 hours. See Roles and permissions.
  • A Server API key (sk_prod_) with the read:device scope. See Authentication.
  • The mobile attestation module enabled for your organisation. Ask your account team if the Attestation Apps page or the routes do not respond for your workspace.
  • Android: the package name and the SHA-256 digest of the app signing certificate.
  • iOS: the bundle ID. The Apple Team ID is optional at registration and required for App Attest verification.
  • For the web Hardware Attestation tabs: the Hardware Attestation add-on subscribed for your workspace and proof-of-work attestation turned on for the domain by a platform administrator. Subscribing never turns on browser compute by itself.

Steps

1. Register your app

Go to Backoffice → Integrations & API → Attestation Apps. The page is titled Mobile attestation apps. Unregistered apps are refused.

  1. Choose Platform: Android or iOS.
  2. Enter a Display name. It is required and can be up to 200 characters.
  3. Fill the platform fields.
  4. Click Register app and complete the step-up prompt if Backoffice asks for it.
PlatformFieldRule
AndroidPackage nameRequired. Example com.example.app.
AndroidSigning certificate SHA-256Required. 64 hex characters. Backoffice lower-cases it.
iOSBundle IDRequired. Example com.example.app.
iOSTeam IDOptional, up to 64 characters. Example TEAMID123.

Each registered app shows an app key. For Android it is the package name. For iOS it is <TeamID>.<BundleID>, or just the bundle ID while no Team ID is set. If you register the same identity twice, Backoffice answers that an app with this identity is already registered.

The verification route uses the package name for Android. The certificate digest is stored with the registration.

If you register an iOS app without a Team ID, native RUM and replay ingestion work for that app. App Attest verification fails closed until you add the Team ID. Use Add Team ID on the app row, enter the ID and click Save. You do not register the app again. The row then shows App Attest configured.

To stop trusting an app, click Revoke on its row and confirm. Devices that use it fail verification from then on. The row is kept as revoked for audit.

2. Mint a nonce from your backend

Call the route for the platform. Both routes take a Server API key as a Bearer token and a JSON body.

curl -X POST https://collect.noxtica.com/v1/attest/android \
  -H "Authorization: Bearer sk_prod_your_server_key" \
  -H "Content-Type: application/json" \
  -d '{"action":"mint"}'

The response:

{ "ok": true, "nonce": "<nonce>", "ttlSeconds": 300, "platform": "android" }

The nonce lives for 300 seconds and works once. You can add "domain_id": "<your-domain-id>" to bind the nonce to a domain. Send the same domain_id when you verify.

Use https://collect.noxtica.com/v1/attest/ios for iOS.

3. Get the token on the device

Send the nonce to the app. The app requests the platform token with that nonce:

  • Android: a Play Integrity standard token whose request hash is the nonce.
  • iOS: an App Attest attestation whose challenge is the nonce.

The mobile SDKs wrap this step. Without an SDK, use the Google and Apple client APIs directly.

4. Verify the token

Send the nonce and the token back through your backend.

curl -X POST https://collect.noxtica.com/v1/attest/android \
  -H "Authorization: Bearer sk_prod_your_server_key" \
  -H "Content-Type: application/json" \
  -d '{"action":"verify","nonce":"<nonce>","integrityToken":"<play-integrity-token>"}'

For iOS send attestationObject (base64) instead of integrityToken. If action is missing, the route treats the call as verify.

Body fieldUsed for
nonceRequired. The value from step 2.
integrityToken or tokenRequired on Android.
attestationObject or tokenRequired on iOS.
app_keyOptional. Selects one of your registered apps. Required when you have more than one active app on the platform.
domain_idOptional. Must match the mint call when you set it there.

The response:

{
  "ok": true,
  "verdict": "pass",
  "verificationLevel": "verified",
  "platform": "android",
  "attestationId": "<id>"
}

Limits for both routes: a body up to 32,768 bytes, Content-Type: application/json, and by default 10 requests per 60 seconds for each API key. Over the limit you get 429 and a Retry-After header.

5. Act on the result in your backend

You receiveWhat to do
pass and verifiedTreat the device as attested for this action.
fail and verifiedThe token was genuine but the policy was not met. Android needs a recognised app and a device that meets device integrity.
fail and structure_onlyThe attestation parsed but was not fully proven. Do not treat it as pass.
fail and unverified, no attestationIdThe nonce was already used, expired, or bound to another platform or domain. Mint a new nonce.
fail and unverified, with attestationIdNothing could be proven, for example the app is not registered. Open the row in Backoffice and read Detail.
errorNoxtica could not record the result. Mint a new nonce and retry.

If your workspace has a webhook subscribed to risk.flagged, each recorded mobile result also sends one event. Its flags list contains mobile_attest:<platform>, mobile_attest_level:<level> and mobile_attest_verdict:<verdict>. See Webhooks.

6. Read results in Backoffice

Go to Backoffice → Device Intelligence → Hardware Attestation → Mobile attestations. The tab is tenant-wide. It is not tied to a website domain.

  • Use the Platform filter for All platforms, Android or iOS.
  • Rows are newest first, 25 to a page.
  • Columns: Recorded at, Platform, Verdict, Verification level, Device binding, Detail.
  • Device binding is a short hash. The single-use nonce is never shown.
  • Detail lists only a fixed set of non-sensitive keys: reason, app_recognition_verdict, device_recognition_verdict, integrity_level, environment and error_code.
  • With fewer than 5 records in the window, the tab hides the list and says Too few records to show.

The tab reads the analytics copy of the ledger. Click Refresh if a recent result is missing.

7. Read the web Hardware Attestation tabs

The Hardware Attestation page has three tabs. Admins and superadmins see all three.

TabWhat it shows
DistributionHow many distinct devices reached each CPU, WebGPU and WebGL2 proof-of-work level. Filters: window (1d, 7d, 30d), device class, hardware bucket, domain.
GPU detailServer-verified GPU attestation: Overview, Events and Distribution sub-tabs, with tiers Hardware, Software, Suspicious, Failed and Unavailable.
Mobile attestationsThe mobile ledger from step 6.

Levels are not comparable between the CPU, WebGPU and WebGL2 ladders. Read each card on its own. Cells with fewer than 5 devices are hidden for privacy.

Verify it works

  • The app appears in Attestation Apps with the Active badge. An iOS app with a Team ID also shows App Attest configured.
  • The mint call returns a nonce and ttlSeconds of 300.
  • The verify call returns ok: true, a verdict, a verificationLevel and an attestationId.
  • A row for that result appears in Hardware Attestation → Mobile attestations after you click Refresh.
  • Revoke a test app and repeat the verify call. The result is now fail and unverified, and the Detail column shows reason=app_not_registered.

Troubleshooting

SymptomCauseFix
429 Rate limit exceeded with Retry-AfterMore than the per-key limit of attest calls in the window.Wait for Retry-After. Ask your account team if you need a higher limit.
415 and Content-Type must be application/jsonThe request has no JSON content type.Send Content-Type: application/json.
413 Payload too largeThe body is over 32,768 bytes.Send only the nonce and the token.
400 and Missing nonce / tokenA verify call without nonce or without the token field.Send both fields.
503 Could not mint challengeNoxtica could not store the nonce.Retry the mint call.
fail and unverified with no attestationIdThe nonce is already used, older than 300 seconds, or minted for another platform or domain_id.Mint a new nonce and verify once. Use the same domain_id in both calls.
Detail shows reason=app_not_registeredNo active registered app matches. With several active apps you also need app_key.Register the app, or send app_key.
iOS response has error: "app_attest_team_id_missing"The iOS app is registered without a Team ID.Click Add Team ID on the app row.
Android Detail shows reason=not_provisionedGoogle verification is not provisioned for this deployment.Contact your account team.
iOS result is structure_only and failThe certificate check did not complete or was not met. A build signed for the Apple development environment stays at this level and shows reason=aaguid_development.Test with a production-environment build. Contact your account team if production builds behave the same.
Too few records to showFewer than 5 records in the window.Wait for more traffic. Individual rows stay hidden below the floor.
No mobile attestationsNo device has completed an attestation for this workspace yet.Finish steps 2 to 4 for one device.
Mobile attestation events could not be loadedThe analytics read failed.Click Refresh. Contact support with the time of the attempt if it continues.
Distribution tab says the add-on is not subscribedThe Hardware Attestation add-on is not subscribed for the workspace.Ask your account team. Subscribing is a platform administrator action.
Distribution tab says proof-of-work attestation is not enabledThe add-on is subscribed but no domain in scope has proof-of-work turned on.Ask your account team to turn it on for the domain.