Attest¶
Register this device's signing key with DEA. The SDK creates the key the first time it is needed, inside the Android Keystore or the iOS Secure Enclave, where the private half cannot be read by your app or by the SDK. Where the platform supports it, the registration also carries a Google Play Integrity (Android) or Apple App Attest (iOS) token, so DEA can check the device and the app are genuine.
DEA files the registration under the app your appKey belongs to. See
Accounts and keys.
When to use it¶
- Before a sensitive step, to make sure the device is registered
- To show attestation status in a diagnostics screen
Prerequisites¶
- The SDK is installed and initialized with your
appIdandappKey, and on Android yourplayIntegrityProject. See the Quick Start and Accounts and keys. - The platform setup below.
Platform setup¶
Android: Play Integrity¶
Play only issues a genuine token to an app it recognizes: installed from Google Play, or signed with a key registered in your app's Play Console entry. Test with a build from a Google Play testing track, on a real device with Google Play services.
Pass the Google Cloud project number DEA issued for your Android app as playIntegrityProject. It
must be the project your app is linked to on the App integrity page of Play Console. With any other
number, attest() answers failed.
import {Platform} from 'react-native';
import * as Dea from '@dea/react-native';
await Dea.init({
appId: Platform.OS === 'ios' ? 'YOUR_IOS_APP_ID' : 'YOUR_ANDROID_APP_ID',
appKey: Platform.OS === 'ios' ? 'YOUR_IOS_APP_KEY' : 'YOUR_ANDROID_APP_KEY',
playIntegrityProject: 123456789012, // read on Android only
});
iOS: App Attest¶
Add the App Attest capability to your app:
- Open
ios/YourApp.xcworkspacein Xcode. - Select your app target, then Signing & Capabilities.
- Click + Capability and add App Attest.
This adds the com.apple.developer.devicecheck.appattest-environment entitlement. Without the
capability, attest() answers failed, and attestation.detail typically mentions invalidKey.
App Attest needs iOS 14 or later on a real device. On the iOS Simulator the registration is sent
without an App Attest token, so platformAttested is false.
Usage¶
Attest¶
import * as Dea from '@dea/react-native';
const attestation = await Dea.attest();
switch (attestation.verdict) {
case 'passed':
// DEA accepted this device's key.
break;
case 'unsupported':
// No key could be created on this device, or no appKey was given. See attestation.detail.
break;
case 'failed':
// DEA refused, or could not be reached. See attestation.detail.
break;
}
attest()does not reject for a refusal, a timeout or a missing keystore: every outcome comes back as anAttestation. It rejects only wheninithas not run.- The result is cached, and survives app restarts, so calling it again costs nothing until shortly before it expires.
- The first call also turns on automatic renewal. From then on the SDK renews the registration
shortly before it expires, and re-plans when the app returns to the foreground. An app that never
calls
attest()never registers a key.
Check whether the platform vouched for the device¶
A passed verdict means DEA accepted the key. It is a statement about the device only when
platformAttested is true:
if (attestation.verdict === 'passed' && attestation.platformAttested) {
// Google or Apple confirmed the device and app.
}
platformAttested is false on emulators and simulators, on Android devices without Google Play
services, and on builds Play does not recognize.
Read the last result without attesting again¶
Renew now¶
Renews the registration immediately and re-plans the next automatic renewal. A refusal keeps the registration already held.
Follow automatic renewal¶
Subscribe before the first attest(), which is what schedules the first renewal:
import * as Dea from '@dea/react-native';
const subscription = Dea.onAttestationEvent(event => {
switch (event.type) {
case 'scheduled':
console.log(`renewal in ${event.afterSeconds} s`);
break;
case 'fired':
console.log('renewed:', event.verdict);
break;
case 'idle':
console.log('nothing to renew');
break;
}
});
// later
subscription.remove();
getNextAttestationRefresh() resolves the time of the next automatic renewal, in epoch seconds, or
null when none is planned.
Examples¶
Attest before a payment step¶
import * as Dea from '@dea/react-native';
export async function openPayment(navigation: {navigate: (route: string) => void}) {
const attestation = await Dea.attest().catch(() => null);
if (attestation?.verdict !== 'passed') {
console.warn('DEA attestation:', attestation);
}
navigation.navigate('Payment');
}
API¶
| Member | Returns | Description |
|---|---|---|
attest() |
Promise<Attestation> |
Registers the device key and returns the result; turns on automatic renewal |
renewAttestation() |
Promise<Attestation> |
Renews now and re-plans automatic renewal |
getLastAttestation() |
Promise<Attestation \| null> |
The last result, without attesting again |
getNextAttestationRefresh() |
Promise<number \| null> |
Next automatic renewal, epoch seconds |
onAttestationEvent(listener) |
EventSubscription |
Every decision automatic renewal makes |
Attestation:
| Field | Type | Description |
|---|---|---|
supported |
boolean |
Whether a key could be created on this device |
verdict |
'passed' \| 'failed' \| 'unsupported' |
The outcome |
platformAttested |
boolean |
Whether Play Integrity or App Attest vouched for the device |
expiresAt |
number \| null |
Expiry, in epoch seconds |
kid |
string \| null |
The key's identifier |
tier |
string \| null |
The trust tier DEA assigned |
backing |
string \| null |
Where the key is kept on the device |
detail |
string \| null |
Why attestation failed, when it did |