App Attest

RSS for tag

Validate the integrity of your app before your server provides access to sensitive data.

Posts under App Attest tag

25 Posts

Post

Replies

Boosts

Views

Activity

App Attest receipts response 400
I tried to send it on the nodejs server I built. No success received 200 My work steps are as follows: The app executes “DCAppAttestService.shared.attestKey” to get receiptData from the acquired attestation. The app sends "receiptData.base64EncodedString()" to the server (code-1) Nodejs code (code-2) Because the app has been uploaded to TestFlight, I set the server IP to "data.appattest.apple.com" Is there something wrong with my steps? code-1 public func attestData(receipt:Data) { if DCDevice.current.isSupported { let sesh = URLSession(configuration: .default) var req = URLRequest(url: URL(string: "http://10.254.239.27:3000/attestationData")!) print(req) req.addValue("application/json", forHTTPHeaderField: "Content-Type") req.httpMethod = "POST" let data = try! JSONSerialization.data(withJSONObject: ["receipt": receipt.base64EncodedString()], options: []) req.httpBody = data let task = sesh.dataTask(with: req, completionHandler: { (data, response, error) in if let data = data, let jsonString = String(data: data, encoding: .utf8) { print(jsonString) } }) task.resume() } else { print("Platform is not supported. Make sure you aren't running in an emulator.") //self.stopActivity() } } code-2 versionRouter.post('/attestationData', function(req, response) { console.log("\n\n\n\n\n"); console.log("receiptApi"); var receiptBase64 = req.body.receipt; if (!receiptBase64) { return response.status(400).send({ error: 'Missing receipt data' }); } let binaryReceipt; if (typeof receiptBase64 === 'string') { const cleaned = receiptBase64.trim(); binaryReceipt = Buffer.from(cleaned, 'base64'); } if (Buffer.isBuffer(binaryReceipt)) { //binaryReceipt = receiptBase64; console.log("receipt is base64 或 Buffer: "+ Buffer.isBuffer(binaryReceipt)); } else { console.error('⚠️ receipt is not base64 or Buffer'); response.status(400).send("Receipt format error"); return; } var jwToken = jwt.sign({}, cert, { algorithm: 'ES256',header: { typ: undefined }, issuer: teamId, keyid: keyId}); var post_options = { host: 'data.appattest.apple.com', port: '443', path: '/v1/attestationData', method: 'POST', headers: { 'Authorization': jwToken, 'Content-Type': 'application/octet-stream', 'Content-Length': binaryReceipt.length } }; var post_req = https.request(post_options, function(res) { res.setEncoding('utf8'); console.log("📨 Apple Response Header:", res.headers); console.log("📨 Apple StatusCode:", res.statusCode); var data = ""; res.on('data', function (chunk) { data += chunk; }); res.on('end', function() { console.log(data); response.send({"status": res.statusCode, data: data}); }); }); post_req.on('error', function(e) { console.error('error:', e); response.status(500).send({ error: e.message }); }); post_req.write(binaryReceipt); post_req.end(); });
1
0
193
Apr ’25
App Attest API – "DCErrorInvalidKey 3" after App or OS Update
Hi everyone, We are using the App Attest API to securely transition users to our new system. As part of this, we store the Key ID of the attestation key for each user to verify their identity later. However, we’ve noticed that some users are encountering the error “DCErrorInvalidKey 3” when calling generateAssertion. Importantly, the key was previously successfully attested, and generateAssertion has worked before for these users. Our questions: Could this error be caused by an app or iOS update? Is it problematic to link an attestation key's Key ID directly to a user, or are there scenarios where the key might change or become invalid? If there’s a way to mitigate this issue or recover affected users, what best practices would you recommend? Any help or shared experiences would be greatly appreciated! Thanks in advance.
0
3
178
Apr ’25
Issue with DCAppAttestService for offloaded app
Hi, When calling generateAssertion on DCAppAttestService.shared, it gives invalidKey error when there was an update for an offloaded app. The offloading and reinstall always works fine if it is the same version on app store that was offloaded from device, but if there is an update and the app tries to reuse the keyID from previous installation for generateAssertion, attestation service rejects the key with error code 3 (invalid key) for a significant portion of our user. In our internal testing it failed for more than a third of the update attempts. STEPS TO REPRODUCE: install v1 from app store generate key using DCAppAttestService.shared.generateKey Attest this key using DCAppAttestService.shared.attestKey Send the attestation objection to our server and verify with apple servers Generate assertions for network calls to backend using DCAppAttestService.shared.generateAssertion with keyID from step 2 Device offloads the app (manually triggered by user, or automatically by iOS) A new version v2 is published to App Store Use tries to open the app Latest version is download from the App Store App tries to use the keyID from step 2 to generate assertions DCAppAttestService throws invalidKey error (Error Domain=com.apple.devicecheck.error Code=3) Step 7 is critical here, if there is no new version of the app, the reinstalled v1 can reuse the key from step 2 without any issues Is this behaviour expected? Is there any way we can make sure the key is preserved between offloaded app updates? Thanks
4
0
424
Feb ’25
How to implement server-side authentication for text filtering requests??
If an app has a text filtering extension and associated server that the iPhone OS communicates with, then how can that communication be authenticated? In other words, how can the server verify that the request is valid and coming from the iPhone and not from some spoofer? If somebody reverse engineers the associated domain urls our of the app's info.plist or entitlement files and calls the server url directly, then how can the server detect this has occurred and the request is not coming from the iPhone OS of a handset on which the app is installed?
16
1
762
Jan ’25