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

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

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.3.3.tar.gz (12.7 kB view details)

Uploaded Source

Built Distribution

devicecheck-1.3.3-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: devicecheck-1.3.3.tar.gz
  • Upload date:
  • Size: 12.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for devicecheck-1.3.3.tar.gz
Algorithm Hash digest
SHA256 d7ade9006b84b47fc865c56c38f8b9600163d746a6bee9ac32c66536d4f1aadf
MD5 87fecbfda2c1bbd0c28459b7564402a5
BLAKE2b-256 32e02d6da0d60f32a34dad0f25781b0e9b0ccd195297a3cde092c1629bd93d97

See more details on using hashes here.

File details

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

File metadata

  • Download URL: devicecheck-1.3.3-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for devicecheck-1.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 682251d7a95e11974b1590637da40ef7c1cca49e304e8588817ffa8f42cd465b
MD5 9929cd0248b729fa6cd7014dfa91f8a6
BLAKE2b-256 c4dc4bc7f09a0f69b2d39ce88160ec7c17afd7736d6a058a930d582e0c28a8a1

See more details on using hashes here.

Supported by

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