Validate a device
- Requests a one-time challenge from the server
- Generates or retrieves an attestation key via Apple’s App Attest
- Creates an attestation object on-device
- Sends it to the Grantiva server for validation
- Returns a signed JWT with device intelligence
AttestationResult
DeviceIntelligence
Token caching
The SDK automatically caches valid tokens. CallingvalidateAttestation() multiple times reuses the cached token until it expires, then performs a fresh attestation.
Refresh tokens
Check if the current token is still valid, and refresh if expired:nil if no token has been stored yet (call validateAttestation() first).
Check token status
Clear stored data
Force a fresh attestation on the next call:Use the token
Send the JWT to your backend as a Bearer token:- Device risk score
- Jailbreak detection status
- Device model and OS version
- Custom claims configured in the dashboard
Challenges
Every attestation starts with a one-time challenge from the server. The SDK requests it automatically, but understanding the rules helps when debugging:- Challenges are valid for 5 minutes. A slow attestation flow (e.g. paused in the debugger) can outlive its challenge — the server returns
challenge_expiredand the SDK requests a fresh one. - Challenges are single-use. Replaying a challenge returns
challenge_already_used. Never cache or share challenges between attestation attempts. - The
clientDataHashsent to Apple must be the SHA256 of the exact challenge string. A mismatch surfaces asclient_data_hash_invalid.
Troubleshooting
Common causes when the server rejects an attestation (apple_validation_failed):
- Bundle ID / Team ID mismatch — the values in the request don’t match what App Attest signed against. Check that the SDK’s
teamIdmatches your Apple Developer Team ID and the build’s bundle identifier is registered in the dashboard. - Running in the Simulator — App Attest only works on real hardware. Use API key mode for Simulator and CI builds.
- Reused or tampered attestation object — attestation objects are single-use and bound to their challenge.
- Key state drift (
reattest_required, HTTP 409) — the device’s stored App Attest key no longer matches the server’s records (backup restore, device transfer). The SDK self-heals by clearing local key state and re-attesting; you’ll only see the error if that retry also fails. - MAD limit reached (HTTP 402) — new device onboarding is paused because your plan’s Monthly Active Device limit was exceeded and the grace period ended. See Billing.