Skip to main content

Apple DeviceCheck

Accessing and Modifying Per-Device Data

Use a token from your app to validate requests, query and modify two per-device binary digits stored on Apple servers.

Features

  • Prevent API & Content abuse with validating requests via Apple device token
  • Query and modify two bits of data to achieve up to four remote states saved on Apple servers
  • Easy to use configuration
  • Examples
  • Integrations with modern web frameworks

Prepare

Visit https://developer.apple.com/account/resources/authkeys/list and create new Key with DeviceCheck permission

Install

pip install devicecheck

Usage (Python)

Setup

from devicecheck import DeviceCheck

device_check = DeviceCheck(
    team_id="XX7AN23E0Z",  # https://developer.apple.com/account/#/membership/
    bundle_id="com.akentev.app",
    key_id="JSAD983ENA",  # Generated at https://developer.apple.com/account/resources/authkeys/list
    private_key="/path/to/AuthKey_JSAD983ENA.p8",
    # Generated file at https://developer.apple.com/account/resources/authkeys/list
    dev_environment=True,  # True if using development Apple environment, False if using in production.
    # Remember to set dev_environment=False in production!
)

Asyncio setup

from devicecheck.asyncio import AsyncioDeviceCheck

The rest will be the same, except for network methods must be await'ed

Validate device

result = device_check.validate_device_token(device_token)

if result.is_ok:
    print('OK! Device is valid')
else:
    print('Bad news. Unable to validate device')

Update bits data

# Can use both integers, strings and booleans. Will be converted with bool(value)
result = device_check.update_two_bits(device_token, bit_0=1, bit_1=False)

# Can update bits separately
result = device_check.update_two_bits(device_token, bit_0=True)

if result.is_ok:
    print('Bits updated')
else:
    print(f'Something went wrong. {result}')

Query bits data

# Can use both integers, strings and booleans
result = device_check.query_two_bits(device_token)

if result.is_ok:
    print(f'First bit {result.bit_0}')  # True
    print(f'Second bit {result.bit_1}')  # False
    print(f'Last update time {result.bits_last_update_time}')  # 2020-04
else:
    print(f'Something went wrong. {result}')

Web server decorators

You can easily integrate devicecheck to your webserver using a decorator. Specify a supported framework, or leave None to try universal parser.

from devicecheck.decorators import validate_device  # for sync code
from devicecheck.decorators import DCSupportedFrameworks
from devicecheck import DeviceCheck

device_check = DeviceCheck(...)

# Set response that will be returned on invalid token
INVALID_TOKEN_RESPONSE = ('Invalid device_token', 403)


@app.route('/validate')
@validate_device(device_check, framework=DCSupportedFrameworks.flask, on_invalid_token=INVALID_TOKEN_RESPONSE)
def endpoint():
    return 'Content'

Sync code

Use sync decorator

from devicecheck.decorators import validate_device
from devicecheck.decorators import DCSupportedFrameworks

Flask

INVALID_TOKEN_RESPONSE = ('Invalid device_token', 403)
framework = DCSupportedFrameworks.flask

Async code

Use Async decorator

from devicecheck.decorators import async_validate_device
from devicecheck.decorators import DCSupportedAsyncFrameworks

Sanic

from sanic.response import text

INVALID_TOKEN_RESPONSE = text('Invalid device_token', status=403)
framework = DCSupportedAsyncFrameworks.sanic

FastAPI

from fastapi.responses import PlainTextResponse

INVALID_TOKEN_RESPONSE = PlainTextResponse('Invalid device_token', status_code=403)
framework = DCSupportedAsyncFrameworks.fastapi

Tests & Mock

Well, it's kinda hard to automate testing, because Devicecheck requires real device (Simulators won't work). In case you need to disable decorators, pass SKIP_DEVICE_CHECK_DECORATOR=True environment variable.

You can also mock validation, pass MOCK_DEVICE_CHECK_DECORATOR_TOKEN=XXXXXXXXXXXXX, it will be a hardcoded valid token value.

MOCK_DEVICE_CHECK_DECORATOR_TOKEN="device-check-token" python -m unittest tests/integrational/main.py

For Debug logs, including requests body, pass a DEBUG environment variable.

Exceptions

Library represents an AppleException class with attributes status_code and description Requires raise_on_error=True parameter for DeviceCheck instance.

Usage (Swift)

Generate device token

import DeviceCheck

public func getDeviceToken(completion: @escaping (String?) -> ()) {
    if #available(iOS 11.0, *) {
        let currentDevice = DCDevice.current
        if currentDevice.isSupported
        {
            currentDevice.generateToken(completionHandler: { (data, error) in
                if let tokenData = data {
                    let tokenString = tokenData.base64EncodedString()
                    print("Received device token")
                    completion(tokenString)
                } else{
                    print("Error generating token: \(error!.localizedDescription)")
                }
            })
        } else {
            print("Device is not supported") // Simulators or etc.
        }
    } else {
        print("Device OS is lower than iOS 11")
    }
}

Pass device token in HTTP request

Header or Body

getDeviceToken { deviceToken in
    var request = URLRequest(url: "...")
    request.httpMethod = "POST"
    
    // Header
    request.setValue(deviceToken, forHTTPHeaderField: "Device-Token")
    
    // Body
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    let json = ["device_token": deviceToken] as [String : Any]
    let jsonData = try! JSONSerialization.data(withJSONObject: json)
    request.httpBody = jsonData as Data
    
    // Send it to server
    let downloadTask = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
        ...
    })
}

License

MIT

Release files for devicecheck 1.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for devicecheck 1.3.3
File Size Uploaded
devicecheck-1.3.3.tar.gz 12.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for devicecheck 1.3.3
File Interpreter ABI Platform
devicecheck-1.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 24.9 kB

Release files / devicecheck-1.3.3.tar.gz

Download URL devicecheck-1.3.3.tar.gz
Size 12.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d7ade9006b84b47fc865c56c38f8b9600163d746a6bee9ac32c66536d4f1aadf
BLAKE2b-256 checksum
How to use checksums
32e02d6da0d60f32a34dad0f25781b0e9b0ccd195297a3cde092c1629bd93d97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.12.3

Release files / devicecheck-1.3.3-py3-none-any.whl

Download URL devicecheck-1.3.3-py3-none-any.whl
Size 12.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
682251d7a95e11974b1590637da40ef7c1cca49e304e8588817ffa8f42cd465b
BLAKE2b-256 checksum
How to use checksums
c4dc4bc7f09a0f69b2d39ce88160ec7c17afd7736d6a058a930d582e0c28a8a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

1.3.3 This release

2 release files

1.3.0

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page