Skip to content

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. With the key, the SDK sends a Google Play Integrity token (Android) or an Apple App Attest token (iOS), so DEA can check that the device and the app are genuine before it accepts the key.

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. See the Quick Start.
  • The values DEA issued for this platform's app are passed to DeaSdk.init: appId and appKey on both platforms, and playIntegrityProject on Android. See Options.
  • The platform setup below.

Platform setup

Android: Play Integrity

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.

DEA's service reads the token before it accepts the key. It requires that Google Play recognizes the app and that this copy was installed through Google Play, and that the device meets Play's device-integrity check. A build installed from a file, or signed with a key that is not registered in your app's Play Console entry, therefore fails attestation. Test with a build from a Google Play testing track, on a real device with Google Play services.

DeaSdk.init(
  const DeaOptions(appId: 'YOUR_APP_ID'),
  appKey: 'YOUR_APP_KEY',
  playIntegrityProject: 123456789012, // read on Android only
);

iOS: App Attest

Add the App Attest capability to your app:

  1. Open ios/Runner.xcworkspace in Xcode.
  2. Select the Runner target, then Signing & Capabilities.
  3. Click + Capability and add App Attest.

This adds the com.apple.developer.devicecheck.appattest-environment entitlement with the value development, Apple's App Attest sandbox, which builds you run from Xcode use. A build distributed through TestFlight, the App Store or the Apple Developer Enterprise Program ignores the value and uses Apple's production environment. Without the capability, App Attest refuses every key: attest() answers failed, and attestation.detail typically mentions invalidKey.

App Attest needs iOS 14 or later on a real device. On the iOS Simulator, and on iOS 12 and 13, the SDK sends the registration without an App Attest token, so platformAttested is false.

Usage

Attest

import 'package:dea_sdk/dea_sdk.dart';

final attestation = await DeaSdk.instance!.attest();

switch (attestation.verdict) {
  case Verdict.passed:
    // DEA accepted this device's key.
    break;
  case Verdict.unsupported:
    // No key could be created on this device, or no appKey was given. See attestation.detail.
    break;
  case Verdict.failed:
    // DEA refused, could not be reached, or the platform would not issue its token.
    // See attestation.detail.
    break;
}
  • attest() never throws.
  • A passed result is kept, on the device as well, until one minute before it expires, so calling attest() again costs nothing until then. A failed or unsupported result is not kept: the next call tries again.
  • One exception: after DEA refuses a registration that carried a platform token, the SDK waits before it asks Google or Apple for another — one hour, doubling with each further refusal up to seven days. Until then attest() answers failed without contacting anyone, and detail says until when.

Check whether a platform token was sent

platformAttested says whether a Play Integrity or App Attest token went to DEA with the key:

if (attestation.verdict == Verdict.passed && attestation.platformAttested) {
  // DEA accepted the key together with Google's or Apple's token.
}

It is false when the platform had no token to give: on the iOS Simulator, and on iOS 12 and 13. When Google or Apple refuses to issue a token, attest() answers failed instead, with the platform's reason in detail.

Read the last result without attesting again

final last = DeaSdk.instance?.attestation; // null before the first attest() in this run

attestation is whatever the last attest() answered in this run, including a refusal.

Check for an existing registration without contacting DEA

final stored = await DeaSdk.instance?.storedAttestation();
// null: attest() would have to register the device again

storedAttestation() reads the registration kept on the device, without any network request and without asking Google or Apple for a token. It returns null when there is none or it is about to expire.

Examples

Attest before a payment step

import 'package:dea_sdk/dea_sdk.dart';
import 'package:flutter/material.dart';

Future<void> openPayment(BuildContext context) async {
  final attestation = await DeaSdk.instance?.attest();

  if (attestation?.verdict != Verdict.passed) {
    debugPrint('DEA attestation: $attestation, ${attestation?.detail}');
  }

  if (context.mounted) {
    Navigator.of(context).pushNamed('/payment');
  }
}

API

Member Returns Description
attest() Future<Attestation> Registers the device key and returns the result
attestation Attestation? The last result in this run, without attesting again
storedAttestation() Future<Attestation?> The registration kept on the device, if still fresh; no network
forgetAttestation() Future<void> Forgets the registration, so the next attest() registers again

Attestation:

Field Type Description
supported bool Whether a key could be created on this device. false also when no appKey was given
verdict Verdict passed, failed or unsupported
platformAttested bool Whether a Play Integrity or App Attest token went to DEA with the key
expiresAt int? Expiry, in epoch seconds
kid String? The key's identifier
tier String? The trust tier DEA assigned
backing String? Where the key is kept on the device: strongbox, tee, secure_enclave or software
integrity String? DEA's reading of the device's integrity. DEA's service does not send one at present, so it is null
detail String? Why attestation failed or is unsupported