Decoding and Debugging Apple Receipts

Paul Hackenberger
Axel Springer Tech
Published in
3 min readDec 11, 2023

Tackling the implementation of In-App Purchases is always a challenge.
You can test your implementation in the Sandbox, but even then sometimes you want to look into the encrypted receipt to check if the granted productIds and periods match your expectations.

But how can you do that easily, without passing your shared secret to any website, that you can’t trust per default, like AppHud?

Get the Receipt

First of all, you need to get your hands on a receipt. You can either grab this from inside the app via Swift code, or you can use a proxy like Charles or Proxyman to sniff the SSL connections and grab the data from there.

Now you have the App Store receipt, a binary encrypted file signed with an Apple certificate, but how you can extract the productIds and periods that you are interested in?

Reading receipt information

Luckily for us, there is a nice nodejs package available, that provides all required logic for us.

To use the library you need to have access to the App Store Connect App-Specific Shared Secret, that you can find here:

Screenshot of App Store Connect

Now you NEVER want to hard-code secrets in code, and even better have NO secrets plain-text in your environment variables or a local file.

Secure Access to locally saved Shared Secret

Why does it matter if you have a plain-text secret on your machine? Isn’t it safe enough ON my computer IN the company VPN?

Essentially, the security approach to prevent attacks has undergone a shift. Initially, the focus was on making it challenging for attackers to infiltrate the VPN, and once inside, viewing the VPN as a secure zone.
However, real-world attacks necessitate acknowledging that once the initial defense is breached, attackers can exploit various security vulnerabilities to gain control of internal systems.

Consequently, the VPN is no longer deemed a secure zone but rather a battleground. Each server and laptop within it should be fortified to the highest extent possible to thwart potential attack vectors originating from within the VPN.

Given this context, how can you safeguard the Shared Secret on your Mac?

The Mac has the built-in KeyChain that protects your secrets, plus it offers a nice shell access to it, too. So, you can add a password to KeyChain:

security add-generic-password -a "$USER" -s 'name_of_your_key' -w 'passphrase'

Which will result in a new password being added to your KeyChain.

Screenshot of KeyChain password

Now, if you want to access this password programmatically, you can use following command, that might trigger a request for authorization to access the value of the password:

security find-generic-password -a "$USER" -s 'name_of_your_key'

Reading the Receipt information… continued

Following this brief security interruption, you may proceed to examine the receipt data. The fundamental JSON structure of the receipt adheres to the following scheme:

{
“appIdentifier”: “de.axelspringer.app”,
“receiptData”: [“…”]
}

Having previously written your Shared Secret to your KeyChain, you can use following nodejs script, to access the information of the receipt(s).

Gist on Github

https://gist.github.com/pkcpkc/53994b1c18662c51651dda0de9b7f87b

Example output

[
{
transactionId: '2000000xxx',
originalTransactionId: '2000000xxx',
bundleId: 'de.axelspringer.xxx',
productId: 'de.xxx',
purchaseDate: 1701946584000,
expirationDate: 1701946884000,
quantity: 1,
web_order_line_item_id: '20000000xxx',
webOrderLineItemId: '20000000xxx'
}
]

I trust this manual proves beneficial to someone, and the brief excursion on safeguarding local secrets offers an additional perspective on securing personal computer secrets effectively.

--

--