{"id":16342918,"url":"https://github.com/veehaitch/devicecheck-appattest","last_synced_at":"2026-03-16T20:01:08.035Z","repository":{"id":45161929,"uuid":"287712692","full_name":"veehaitch/devicecheck-appattest","owner":"veehaitch","description":"Server-side library to validate the authenticity of Apple App Attest artifacts, written in Kotlin.","archived":false,"fork":false,"pushed_at":"2023-07-03T08:27:23.000Z","size":674,"stargazers_count":69,"open_issues_count":4,"forks_count":9,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-03-17T18:53:49.013Z","etag":null,"topics":["apple-appattest","attestation","devicecheck","ios","java","kotlin","security","webauthn"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/veehaitch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-08-15T09:01:40.000Z","updated_at":"2025-02-06T08:12:08.000Z","dependencies_parsed_at":"2022-08-27T19:11:35.964Z","dependency_job_id":"e5f60bde-a3c0-4481-bbed-1a26cab5aa04","html_url":"https://github.com/veehaitch/devicecheck-appattest","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veehaitch%2Fdevicecheck-appattest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veehaitch%2Fdevicecheck-appattest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veehaitch%2Fdevicecheck-appattest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veehaitch%2Fdevicecheck-appattest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/veehaitch","download_url":"https://codeload.github.com/veehaitch/devicecheck-appattest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244711309,"owners_count":20497409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apple-appattest","attestation","devicecheck","ios","java","kotlin","security","webauthn"],"created_at":"2024-10-11T00:05:37.008Z","updated_at":"2026-03-16T20:01:07.937Z","avatar_url":"https://github.com/veehaitch.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Apple App Attest Validation\n\n[![Maven central](https://img.shields.io/maven-central/v/ch.veehait.devicecheck/devicecheck-appattest.svg)](https://search.maven.org/search?q=devicecheck-appattest)\n[![Build status](https://img.shields.io/github/actions/workflow/status/veehaitch/devicecheck-appattest/main.yml?branch=main)](https://github.com/veehaitch/devicecheck-appattest/actions?query=branch%3Amain)\n[![Code coverage](https://img.shields.io/codecov/c/github/veehaitch/devicecheck-appattest)](https://app.codecov.io/gh/veehaitch/devicecheck-appattest/branch/main)\n[![License](https://img.shields.io/github/license/veehaitch/devicecheck-appattest)](http://www.apache.org/licenses/LICENSE-2.0.html)\n[![Written in Kotlin](https://img.shields.io/badge/code-kotlin-A97BFF)](https://kotlinlang.org/)\n![JVM 11 required](https://img.shields.io/badge/jvm-11-blue)\n\nServer-side library to validate the authenticity of Apple App Attest artifacts, including \n1. attestation statements,\n2. assertions, and\n3. receipts (plus requesting a new one from Apple). \n\nThe project targets the JVM in version 11 or later. The library is written purely in Kotlin while leveraging coroutines\nfor asynchronous execution where meaningful. The implementation relies on only two third party dependencies:\n[Bouncy Castle](http://bouncycastle.org) (CMS, ASN.1 parsing) and [Jackson](https://github.com/FasterXML/jackson) \n(CBOR decoding). The software is available under the conditions of the Apache 2.0 license enabling its usage in most\ncircumstances.\n\nThe implementation follows the steps outlined in the articles [\"Validating Apps That Connect to Your Server\"](https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server)\nand [\"Assessing Fraud Risk\"](https://developer.apple.com/documentation/devicecheck/assessing_fraud_risk) at Apple Developer.\n\n## Getting Started\n\nThe library is published to [Maven Central](https://search.maven.org/search?q=devicecheck-appattest).\n\n#### Gradle (Kotlin)\n\n```kotlin\ndependencies {\n    implementation(\"ch.veehait.devicecheck:devicecheck-appattest:$latestVersion\")\n}\n```\n\n#### Gradle (Groovy)\n\n```groovy\ndependencies {\n    implementation \"ch.veehait.devicecheck:devicecheck-appattest:$latestVersion\"\n}\n```\n\n#### Maven\n\n```xml\n\u003cdependencies\u003e\n  \u003c!-- ... --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ech.veehait\u003c/groupId\u003e\n    \u003cartifactId\u003edevicecheck-appattest\u003c/artifactId\u003e\n    \u003cversion\u003e${latestVersion}\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003c!-- ... --\u003e\n\u003c/dependencies\u003e\n```\n\n## Usage\n\n### Verify the Attestation\n\nAn iOS app creates an `attestationObject` for a key created through `DCAppAttestService.generateKey()` \nby calling `DCAppAttestService.attestKey()`. Make sure the `clientDataHash` comprises a payload which includes a\nchallenge you created within your backend prior to the app's call to `attestKey`. A good challenge is created\nrandomly, only used once (i.e., one challenge per attestation) and large enough to prevent guessing.\n\n```swift\nlet service = DCAppAttestService.shared\n\nservice.generateKey { keyId, error in\n    guard error == nil else { /* Handle the error. */ }\n    // Store keyId for subsequent operations.\n}\n\nservice.attestKey(keyId, clientDataHash: hash) { attestationObject, error in\n    guard error == nil else { /* Handle error and return. */ }\n    // Send attestationObject to your server for verification.\n}\n```\n\nThe server implementation receives the `attestationObject`, e.g., Base64 encoded, and the `keyId`. The `keyId` returned \nfrom `DCAppAttestService.generateKey()` is already Base64 encoded (or more precisely, it is the Base64 encoded SHA-256\ndigest of the public key of the generated key).\n\nTo validate the authenticity of the `attestationObject`, instantiate an `AttestationValidator` for the `App` which \ncalls `DCAppAttestService`. \n\n```kotlin\n// Create an instance of AppleAppAttest specific to a given iOS app, development team and\n// Apple Appattest environment\nval appleAppAttest = AppleAppAttest(\n    app = App(\"6MURL8TA57\", \"de.vincent-haupert.apple-appattest-poc\"),\n    appleAppAttestEnvironment = AppleAppAttestEnvironment.DEVELOPMENT,\n)\n\n// Create an AttestationValidator instance\nval attestationValidator = appleAppAttest.createAttestationValidator()\n\n// Validate a single attestation object. Throws an AttestationException if a validation\n// error occurs.\nval result: ValidatedAttestation = attestationValidator.validate(\n    attestationObject = Base64.getDecoder().decode(\"o2NmbXRvYXBwbGUtYXBwYXR0ZXN0Z2F ...\"),\n    keyIdBase64 = \"XGr5wqmUab/9M4b5vxa6KkPOigfeEWDaw7tuK02aJ6c=\",\n    serverChallenge = \"wurzelpfropf\".toByteArray(),\n)\n```\n\nIf the method call returns, the validation has passed and you can now trust the\n[returned result](https://github.com/veehaitch/devicecheck-appattest/blob/main/src/main/kotlin/ch/veehait/devicecheck/appattest/attestation/ValidatedAttestation.kt)\nwhich contains references to the attestation certificate and the verified receipt.\nYou use the public key of the attestation certificate for the verification of\nassertions and the receipt for obtaining a fraud risk metric.\n\nAlso refer to [AttestationValidatorTest](src/test/kotlin/ch/veehait/devicecheck/appattest/attestation/AttestationValidatorTest.kt).\n\n### Verify the Assertion\n\nAs soon as you validated the attestation statement, your app may leverage the attested public key to create assertions\nfor arbitrary payloads using the App Attest service:\n\n```swift\nservice.generateAssertion(keyId, clientDataHash: clientDataHash) { assertionObject, error in\n    guard error == nil else { /* Handle the error. */ }\n    // Send the assertion and request to your server.\n}\n```\n\nIt is worthwhile to note that the returned `assertionObject` does not contain the `keyId` by itself. You have to include\nit in the data which accompanies the `assertionObject`. Make sure to not rely on the `keyId` to establish a link to any\nidentity in your systems _prior to verifying_ the assertion's authenticity by calling `AssertionValidator.validate()`:\n\n```kotlin\n// Initialize AppleAppAttest as above\n\nval assertionChallengeValidator = object : AssertionChallengeValidator {\n    override fun validate(\n        assertionObj: Assertion,\n        clientData: ByteArray,\n        attestationPublicKey: ECPublicKey,\n        challenge: ByteArray,\n    ): Boolean = TODO(\"Your application specific challenge validation routine\")\n}\n\nval assertionValidator = appleAppAttest.createAssertionValidator(\n    assertionChallengeValidator\n)\n\nval assertion = assertionValidator.validate(/* ... */)\n```\n\nIf the call returns, the app successfully proved control of the attested device. Make sure to include a challenge which\nsuits the security demands of your service. A safe approach is to issue server-side per-assertion challenges, similar\nto those created for the initial attestation statement (see above).\n\nAlso refer to [AssertionValidatorTest](src/test/kotlin/ch/veehait/devicecheck/appattest/assertion/AssertionValidatorTest.kt)\n\n### Assess Fraud Risk with Receipts\n\nSee [ReceiptValidatorTest](src/test/kotlin/ch/veehait/devicecheck/appattest/receipt/ReceiptValidatorTest.kt) and \n[ReceiptExchangeTest](src/test/kotlin/ch/veehait/devicecheck/appattest/receipt/ReceiptExchangeTest.kt).\n\n## Contributions\n\nYour contributions are welcome! Just submit a pull request. Also, if you have a question, feel free to open an issue.\n\n## License\n\n[Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveehaitch%2Fdevicecheck-appattest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fveehaitch%2Fdevicecheck-appattest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveehaitch%2Fdevicecheck-appattest/lists"}