---
title: Validating apps that connect to your server
framework: DeviceCheck
role: article
role_heading: Article
path: devicecheck/validating-apps-that-connect-to-your-server
---

# Validating apps that connect to your server

Verify that connections to your server come from legitimate instances of your app.

## Overview

Overview Adopt App Attest to check whether clients connecting to your server are valid instances of your app. Your app uses the shared instance of the DCAppAttestService to create a cryptographic key on a device, and then attest to the key’s validity. This produces an attestation object that your app passes to your server, along with the corresponding key identifier. Your server verifies the attestation object, and then extracts the embedded public key and other information. Later, your server uses the key to verify assertion objects that your app sends at critical points in the app’s life cycle, like when users try to download premium content.

This article describes how to integrate App Attest into your server logic. For more information about the activites you perform in your app to support App Attest, see Establishing your app’s integrity. Provide a challenge Every time your app needs to communicate attestation data to your server, the app first asks the server for a unique, one-time challenge. App Attest integrates this challenge into the objects that it provides, and that your app sends back to your server for validation. This makes it harder for an attacker to implement a replay attack. When the app asks for a challenge, provide a randomized data value, and remember the value for use when verifying the corresponding attestation or assertion objects the client sends. How you use the challenge data depends on the kind of object that you need to validate. Verify the attestation The App Attest service creates an attestation object that consists of authenticator data and an attestation statement according to the Web Authentication specification. The following authenticator fields are of particular interest for App Attest: RP ID (32 bytes) — A hash of your app’s App ID, which is the concatenation of your app’s App ID prefix, a period, and your app’s CFBundleIdentifier value. The App ID prefix is usually automatically set to be your 10-digit team identifier, and can be found by inspecting the Identifier entry for your app in the Certificates, Identifiers & Profiles section of your Apple Developer Account. note: On macOS, the RP ID utilizes the signing identifier in place of the bundle identifier. counter (4 bytes) — A value that reports the number of times your app has used the attested key to sign an assertion. aaguid (16 bytes) — An App Attest–specific constant that indicates whether the attested key belongs to the development or production environment. Apps generate keys using the former during development, and the latter after distribution, as App Attest Environment describes. credentialId length (2 bytes) — The length of the hash of the public key part of the attested cryptographic key pair, following this field. credentialId (32 bytes) — A hash of the public key part of the attested cryptographic key pair. Encoded key (77 bytes) — The CBOR object signing and encryption (COSE) formatted public key part of the attested cryptographic key pair. extensions (variable bytes) — CBOR dictionary object that includes optional client properties. note: An attestation RP ID that an App Clip generates uses the full app’s identifier, not the App Clip’s identifier. For information about the difference between the two, see Creating an App Clip with Xcode. The attestation statement uses a custom Apple attestation statement format with the following syntax: $$attStmtType //= (                       fmt: "apple-appattest",                       attStmt: StmtFormat                   )

StmtFormat =      {                       x5c: [ credCert: bytes, * (caCert: bytes) ],                       receipt: bytes,                   } To verify and decode the attestation object, check that it has the Concise Binary Object Representation (CBOR) data format with the expected syntax. The decoded object looks like this: {   fmt: 'apple-appattest',   attStmt: {     x5c: [       <Buffer 30 82 02 cc ... >,       <Buffer 30 82 02 36 ... >     ],     receipt: <Buffer 30 80 06 09 ... >   },   authData: <Buffer 21 c9 9e 00 ... > } Use the decoded object, along with the key identifier that your app sends, to perform the following steps: Verify that the x5c array contains the intermediate and leaf certificates for App Attest, starting from the credential certificate in the first data buffer in the array (credcert). Verify the validity of the certificates using Apple’s App Attest root certificate. Create clientDataHash as the SHA256 hash of the one-time challenge your server sends to your app before performing the attestation, and append that hash to the end of the authenticator data (authData from the decoded object). Generate a new SHA256 hash of the composite item to create nonce. Obtain the value of the credCert extension with OID 1.2.840.113635.100.8.2, which is a DER-encoded ASN.1 sequence. Decode the sequence and extract the single octet string that it contains. Verify that the string equals nonce. important: On macOS, obtain the value of the aclBlob for the key associated with the attestation with OID 1.2.840.113635.100.8.6, which is a DER-encoded ASN.1 sequence. Decode the sequence and extract the single octet string that it contains. Verify that the string equals MEAMAjExMDowCQwCb2uhAwEB/zAJDAJvYaEDAQH/MAsMBG9kZWyhAwEB/zAVDARvc2duoAYMBHJzZWMwBaYDAgEB. This String value represents the encoded hash of the access policy for the attested key on macOS corresponding with both SIP and full security mode enabled. Attested keys on macOS should only be trusted for this exact hash value. This value should never change across macOS versions. Create the SHA256 hash of the public key in credCert with X9.62 uncompressed point format, and verify that it matches the key identifier from your app. Compute the SHA256 hash of your app’s App ID, and verify that it’s the same as the authenticator data’s RP ID hash. Verify that the authenticator data’s counter field equals 0. Verify that the authenticator data’s aaguid field is either appattestdevelop if operating in the development environment, or appattest followed by seven 0x00 bytes if operating in the production environment. Verify that the authenticator data’s credentialId field is the same as the key identifier. Verify the apple_validation_category_01 value within the extensions CBOR dictionary in the authenticator data. note: This UInt32 value represents the launch ValidationCategory of your app.  |   |   |   |   |   |   |   |   |   |  Verify the apple_bundle_version_01 value within the extensions CBOR dictionary in the authenticator data. note: This String value representing the version of the distributed App. After successfully completing these steps, you can trust the attestation object. note: Follow the Attestation Object Validation Guide to ensure your implementation for the steps above is correct. Store the public key and receipt Store the verified public key from credCert on your server and associate it with the user for the specific device. You use this key to check assertions later. As an added protection against replay attacks, make sure that the public key doesn’t already have an association with another user. The attestation statement also contains a receipt that you can use later in a server-to-server call to request a fraud assessment metric from Apple. You use the metric to examine the number of attested keys for a specific device. This helps you to assess the risk that an attacker is using a compromised device to serve assertions to many compromised versions of your app. When attestation succeeds, independently verify and store the receipt immediately. For more information about how to interpret the receipt, and how to use a receipt to obtain or refresh the metric, see Assessing fraud risk. important: Be prepared to store multiple (key, receipt) pairs for each user. Store one pair for each device the user uses to access your services. Also, keep development pairs separate from production pairs because you can’t use one set in the other’s environment. Verify the assertion After successful attestation, your server can require the associated client to accompany server requests with an assertion object. Each verified assertion reestablishes the legitimacy of the client. You typically require this for requests that access sensitive or premium content. The client creates the assertion by packaging the request as clientData, and asking the App Attest service to sign the data with the attested private key. Along with the signature, App Attest includes a simplified authenticator data instance in the assertion object, similar to the one in the attestation object, but containing only the first few fields, including RP ID and counter. After receiving the client data and the assertion, you need to verify and decode the assertion to ensure it uses the CBOR data format and has the expected contents. The decoded object looks like this: {   signature: <Buffer 30 45 02 20 ... >,   authenticatorData: <Buffer 21 c9 9e 00 ... > } To verify the assertion, use the decoded assertion, the client data, and the previously stored public key, and follow these steps: Compute clientDataHash as the SHA256 hash of clientData. Concatenate authenticatorData and clientDataHash, and apply a SHA256 hash over the result to form nonce. Use the public key that you store from the attestation object to verify that the assertion’s signature is valid for nonce. Compute the SHA256 hash of the client’s App ID, and verify that it matches the RP ID in the authenticator data. Verify that the authenticator data’s counter value is greater than the value from the previous assertion, or greater than 0 on the first assertion. Verify that the embedded challenge in the client data matches the earlier challenge to the client. Verify the validationCategory within the extensions CBOR dictionary in the authenticator data. Verify the bundleVersion within the extensions CBOR dictionary in the authenticator data. When the assertion meets all of these conditions, you can trust it. Store counter to use in step 5 when verifying the next assertion.

## See Also

### App Attest

- [Establishing your app’s integrity](devicecheck/establishing-your-app-s-integrity.md)
- [Assessing fraud risk](devicecheck/assessing-fraud-risk.md)
- [Preparing to use the app attest service](devicecheck/preparing-to-use-the-app-attest-service.md)
- [Attestation Object Validation Guide](devicecheck/attestation-object-validation-guide.md)
- [DCAppAttestService](devicecheck/dcappattestservice.md)
- [App Attest Environment](bundleresources/entitlements/com.apple.developer.devicecheck.appattest-environment.md)
