28.4 · JWS, certificate chains, notifications, the Server API and why receipts gave way to transactions

The device is untrusted territory. Anything worth money gets re-checked on a server that can verify Apple's signature and keep the state when the app is closed.

Mental model. Everything Apple sends is a signed JWS. Verify the chain to Apple's root, verify the signature, then treat the payload as one event in a stream that may be duplicated or out of order.

Signed data

JWS anatomy and the certificate chain behind it.

  1. How is a StoreKit JWS built, and what must a server check before trusting signedTransactionInfo? 28.4.1 · L5
    A JWS (the compact serialisation Apple uses) is base64url(header).base64url(payload).base64url(signature). The header contains alg: "ES256" and an x5c array of…
  2. How do you validate the x5c certificate chain of an App Store JWS, and what does the leaf certificate prove? 28.4.2 · L5
    The x5c chain is only meaningful if it ends at a root you already trust: download Apple's root (Apple Root CA G3 for current App Store signing, from Apple's…

Events and APIs

Notifications, the Server API and its JWT, and moving off receipts.

  1. How do App Store Server Notifications V2 behave, and how do you process them idempotently and out of order? 28.4.3 · L5
    Server Notifications V2 are HTTPS POSTs to a URL you configure per environment. The body is {"signedPayload": "<JWS>"}; verify it like any JWS, then read…
  2. How do you authenticate to the App Store Server API, and what do you use it for? 28.4.4 · L5
    The App Store Server API (REST, JSON) is authenticated by a JWT you sign with an In-App Purchase key from App Store Connect (a .p8 ES256 private key, with a…
  3. What replaced the receipt, and how do you grandfather paid users with AppTransaction.originalAppVersion? 28.4.5 · L5
    The legacy model was an app receipt (a PKCS#7 blob at appStoreReceiptURL) that the app sent to Apple's verifyReceipt endpoint; that endpoint is deprecated, the…

More in Purchases & subscriptions