A mobile app talks to Fingerly from a device you do not control. Attestation and integrity signals tell you whether the report came from your genuine app on a genuine, unmodified device.
Android: hardware-backed attestation
On Android 7.0 (API 24) and newer, the SDK uses the device's hardware-backed keystore to attest to a fresh challenge from Fingerly. The server verifies the result. There is nothing to configure.
| Step | What happens |
|---|---|
| 1 | The SDK requests a challenge: 32 random bytes, valid for five minutes, usable once. |
| 2 | The device keystore creates a temporary key attested to that challenge, and the SDK includes the attestation in its report. |
| 3 | Fingerly verifies the attestation against Google's roots, checks it was made for your app and signing certificate, that the device's boot state is verified, and that the challenge is fresh and unused. |
| 4 | A failed check raises the tampering signal, and an app not signed as expected raises cloned_app. |
Because each challenge is consumed on use, a captured report cannot be replayed.
iOS: integrity signals
On iOS, device integrity comes from the SDK's own checks, scored on the server: jailbroken devices, the Simulator, attached instrumentation, intercepted traffic, runtime tampering and developer tooling. Each is a signal with its own weight.
Using the result
async function checkIntegrity(requestId: string) {
const event = await fingerly.events.get(requestId)
const tampered = event.triggers.some((t) => t.signal === 'browser_tampering' || t.signal === 'cloned_app')
if (tampered) return refuse('app integrity')
return allow()
}