Skip to main content

Apple DeviceCheck API. Reduce fraudulent use of your services by managing device state and asserting app integrity.

Project description

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!
)

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

devicecheck-1.2.2.tar.gz (9.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

devicecheck-1.2.2-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file devicecheck-1.2.2.tar.gz.

File metadata

  • Download URL: devicecheck-1.2.2.tar.gz
  • Upload date:
  • Size: 9.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for devicecheck-1.2.2.tar.gz
Algorithm Hash digest
SHA256 846f5185af940a414889641b4a6a23507d1433b040fd9f4f7a5801129056db48
MD5 3328a137968240c3fd3fd2e583435715
BLAKE2b-256 336334e183fe879268f9396c55ac17a25e2422533bab102520bc6e34250c986c

See more details on using hashes here.

File details

Details for the file devicecheck-1.2.2-py3-none-any.whl.

File metadata

  • Download URL: devicecheck-1.2.2-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for devicecheck-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3c19515f88500fd245ba7b4059e77ac2d14a63a4c8b3ab38d131e381838bfebd
MD5 718662b2b0fedf3b3ce7bd739705a824
BLAKE2b-256 fe96f9c1446f818cc6eaa23c736c51fe793cdf4777ee99e2f9ee1f5a9001f588

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page