1. Overview
Using the DeviceCheck
APIs, in combination with server-to-server APIs, you can set and query two bits of data per device, while maintaining user privacy. You might use this data to identify devices that have already taken advantage of a promotional offer that you provide, or to flag a device that you've determined to be fraudulent. The DeviceCheck
APIs also let you verify that the token you receive comes from an authentic Apple device on which your app has been downloaded.
Your app uses the DeviceCheck
APIs to generate an ephemeral token that identifies a device. Your associated server combines this token with an authentication key that you receive from Apple, and uses the result to request access to the per-device bits. After successful authentication, Apple passes the current values of the bits, along with the date they were last modified, to your server. Your server applies its business logic to this information and communicates the results to your app as appropriate.
2. Generate Token
Method generateToken(completionHandler:)
generates a token that identifies the current device.
let currentDevice = DCDevice.current
if currentDevice.isSupported {
currentDevice.generateToken(completionHandler: { (data, error) in
if let tokenData = data {
print("Token: \(tokenData)")
} else {
print("Error: \(error?.localizedDescription ?? "")")
}
})
}
Code available on Github.
Your server uses the generated token in its requests to get or set the persistent bits for the current device. You should treat the token you receive in the completion block as single-use. Although the token remains valid long enough for your server to retry a specific request if necessary, you should not use a token multiple times. Instead, use this method to generate a new token.
Note - The app you use to generate the token must be associated with your developer account; otherwise, the generation request fails.
3. Accessing and Modifying Per-Device Data
After you use the DeviceCheck
APIs to generate an ephemeral token that identifies a device, your server uses HTTP POST commands to send requests to the query and update endpoints. The HTTP header field in each request must contain the authentication key you receive from Apple in a JSON web token (JWT). To create this token, you can use the same steps you use to create a provider authentication token for Apple Push Notification service (APNs)
3.1 Create an APNs authentication token signing key
- In your developer account, go to Certificates, Identifiers & Profiles.
- Under Keys, select All and click the Add button (+) in the upper-right corner.
- Under Key Description, enter a unique name for the signing key.
- Under Key Services, select the APNs checkbox, then click Continue.
- Review the key configuration, then click Confirm.
- Optionally, click Download to generate and download the key now.
If you download the key, it is saved as a text file with a .p8 file extension. Save the file in a secure place because the key is not saved in your developer account and you won’t be able to download it again. - Click Done.
3.2 Create the Payload for a Query Request
To query the bits, you create a JSON payload that contains the fields listed in the table below.
Field name | Type | Description | Required |
---|---|---|---|
device_token | String | Base 64–encoded representation of encrypted device information | Yes |
transaction_id | String | Unique transaction identifier from the associated server | Yes |
timestamp | Long | UTC timestamp from the associated server, in milliseconds since the Unix epoch | Yes |
Here's an example of a payload included in a query request:
{
"device_token" : "qpkCFA2Yy/DFrNpVAWhs4BRA/0PAIuRiUn0jQg1a..."
"transaction_id" : "6r456df4-w3d4-567u-o435-2376674f8uj8",
"timestamp" : 1487716472000
}
When your query request succeeds, you receive a response that contains the fields listed in the table below.
Field name | Type | Description |
---|---|---|
bit0 | Boolean | The value of the first bit |
bit1 | Boolean | The value of the second bit |
last_update_time | String | The date of the last modification, in YYYY-MM format |
3.3 Create the Payload for an Update Request
To update the bits, you create a JSON payload that contains the fields listed in the table below.
Field name | Type | Description | Required |
---|---|---|---|
device_token | String | Base 64–encoded representation of encrypted device information | Yes |
transaction_id | String | Unique transaction identifier from the associated server | Yes |
timestamp | Long | UTC timestamp from the associated server, in milliseconds since the Unix epoch | Yes |
bit0 | Boolean | Value to set for the first bit | No |
bit1 | Boolean | Value to set for the second bit | No |
Here's an example of a payload included in an update request:
{
"device_token" : "qpkCFA2Yy/DFrNpVAWhs4BRA/0PAIuRiUn0jQg1a..."
"transaction_id" : "6r456df4-w3d4-567u-o435-2376674f8uj8",
"timestamp" : 1487716472000,
"bit0" : true,
"bit1" : false
}
So, you’re able to store :
bit0 | bit1 | bit0 & bit1 combination |
---|---|---|
false | false | 00 |
false | true | 01 |
true | false | 10 |
true | true | 11 |
When you set that information, it remains valid and stored by Apple until you manually reset it or until you update it.
If the update was successful, you receive the HTTP response code 200. For a full list of the response codes you can receive, see Understand the HTTP Response Codes.
3.4 Create the Payload for a Device Validation Request
To validate a device, you create a JSON payload that contains the fields listed in the table below.
Field name | Type | Description | Required |
---|---|---|---|
device_token | String | Base 64–encoded representation of encrypted device information | Yes |
transaction_id | String | Unique transaction identifier from the associated server | Yes |
timestamp | Long | UTC timestamp from the associated server, in milliseconds since the Unix epoch | Yes |
Here's an example of a payload included in a device-validation request:
{
"device_token" : "wlkCDA2Hy/CfMqVAShslBAR/0sAiuRIUm5jQg0aJJ2gZl1cs..."
"transaction_id" : "6r456df4-w3d4-567u-o435-2376674f8uj8",
"timestamp" : 1487716472000
}
If the request was successful, you receive the HTTP response code 200. For a full list of response codes you can receive, see Understand the HTTP Response Codes.
3.5 Send the Request
Each request you send to the query and update endpoints must include an authorization header that contains your authentication key. The authentication key must must use the ES256 algorithm and be in the Base 64 URL–encoded JSON web token format. If your token doesn't use this format, you receive a BAD_AUTHENTICATION_TOKEN
HTTP error.
In the curl command you create to send a request, you specify the authorization header and include your authentication key using Bearer , like this:
-H "Authorization: Bearer <GeneratedJWT>" \
Important
Use the base URL shown in the example curl commands—that is, https://api.development.devicecheck.apple.com—only for testing during development. When you're ready to transition to a production environment, you must use the production base URL https://api.devicecheck.apple.com.
To send a query request, your curl command might look similar to the one shown here:
curl -i --verbose -H "Authorization: Bearer <GeneratedJWT>" \ -X POST --data-binary @ValidQueryRequest.json \
https://api.development.devicecheck.apple.com/v1/query_two_bits
To send an update request, your curl command might look similar to the one shown here:
curl -i --verbose -H "Authorization: Bearer <GeneratedJWT>" \ -X POST --data-binary @ValidUpdateRequest.json \ https://api.development.devicecheck.apple.com/v1/update_two_bits
To send a device-validation request, your curl command might look similar to the one shown here:
curl -i --verbose -H "Authorization: Bearer <GeneratedJWT>" \ -X POST --data-binary @ValidValidateDeviceToken Request.json \ https://api.development.devicecheck.apple.com/v1/validate_device_token
4. Understand the HTTP Response Codes
When you use the query and update endpoints to communicate with the server, you may receive one of the response codes listed in the table below.
Code | Descriptive string | Meaning |
---|---|---|
200 | OK | The transaction was successful |
200 | Bit State Not Found | The bit state wasn't found |
400 | Bad Device Token | The device token is missing or badly formatted |
400 | Bad Bits | The bits are missing or badly formatted |
400 | Bad Timestamp | The timestamp is missing or badly formatted |
400 | Bad Authorization Token | The authentication token is missing or badly formatted |
400 | Bad Payload | The payload is missing or badly formatted |
401 | Invalid Authorization Token | The authentication token can't be verified |
401 | Authorization Token Expired | The authentication token has expired |
403 | Forbidden | The specified action isn't allowed |
405 | Method Not Allowed | The endpoint was used incorrectly |
429 | Too Many Requests | Too many requests were sent to the server |
500 | Server Error | An error occurred on the server |
503 | Service Unavailable | The service is unavailable |
Reference
https://developer.apple.com/documentation/devicecheck