Problems with Apple IAP receipts (SOLVED)

We’re setting up the shop for our game and are using Gamesparks as backend to validate/providing the purchased item. Android is now working perfect.
Unfortunately we have a problem with the receipts coming from an Apple IAP. As I understand, the receipt is sent base64 -coded and therefor should look something like this:

MIIvygYJKoZIhvcNAQcCoIIvuzCCL7cCAQExCzAJBgUrDgMCGgUAMIIfawYJKoZIhvcNAQcBoIIfXASCH1gxgh9UMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIB/
...

(example of complete full receipt)

If printing the receipt we are getting:

0\19\6\t*H\r\1\a\2\190\19\2\1\0011\v0\t\6\5+\14\3\2\26\5\0000\3\6\t*H\r\1\a\1\3\4\31\30\n\2\1\b\2\1\1\4\2\22\0000\n\2\1\20\2\1\1\4\2\f\0000\v\2\1\1\2\1\1\4\3\2\1\0000\v\2\1\v\2\1\1\4\3\2\1\0000\v\2\1\15\2\1\1\4\3\2\1\0000\v\2\1\16\2\1\1\4\3\2\1\0000\v\2\1\25\2\1\1\4\3\2\1\0030\f\2\1\n\2\1\1\4\4\22\0024+0\f\2\1\14\2\1\1\4\4\2\2\00\r\2\1\r\2\1\1\4\5\2\3\10\r\2\1\19\2\1\1\4\5\f\0031.00\14\2\1\t\2\1\1\4\6\2\4P2500\18\2\1\3\2\1\1\4\n\f\b0.14.2330\24\2\1\4\2\1\2\4\16\20\nΩE\f~0\27\2\1\0\2\1\1\4\19\f\17ProductionSandbox0\28\2\1\5\2\1\1\4\20\0308\\5`\v`\31jO%0\30\2\1\f\2\1\1\4\22\22\0202019-01-25T14:10:00Z0\30\2\1\18\2\1\1\4\22\22\0202013-08-01T07:00:00Z0%\2\1\2\2\1\1\4\29\f\27com.strangequest.blastlands0<\2\1\6\2\1\1\0044ַ\tIbJ0S3d'q\29\18UfC\16!.\rkS\15\f\24ӬwK\bkɨ0b\2\1\a\2\1\1\4ZhBL1\fk*XD7\16q\r\17z\rE\16\19%\24#t/\4<\28}L467*lR9BׅWm#=-&\vtKY-˘0\1i\2\1\17\2\1\1\4\1_1\1[0\v\2\2\6\2\1\1\4\2\22\0000\v\2\2\6\2\1\1\4\2\f\0000\v\2\2\6\2\1\1\4\2\22\0000\v\2\2\6\2\1\1\4\2\f\0000\v\2\2\6\2\1\1\4\2\f\0000\v\2\2\6\2\1\1\4\2\f\0000\v\2\2\6\2\1\1\4\2\f\0000\v\2\2\6\2\1\1\4\2\f\0000\f\2\2\6\2\1\1\4\3\2\1\0010\f\2\2\6\2\1\1\4\3\2\1\0010\f\2\2\6\2\1\1\4\3\2\1\0000\f\2\2\6\2\1\1\4\3\2\1\0000\f\2\2\6\2\1\1\4\3\2\1\0000\27\2\2\6\2\1\1\4\18\f\01610000004974829280\27\2\2\6\2\1\1\4\18\f\01610000004974829280\31\2\2\6\2\1\1\4\22\22\0202019-01-25T14:10:00Z0\31\2\2\6\2\1\1\4\22\22\0202019-01-25T14:10:00Z0/\2\2\6\2\1\1\4&\f$com.strangequest.blastlands.hc_xxs_2\14e0\5|0\4d\3\2\1\2\2\b\14W\t0\r\6\t*H\r\1\1\5\5\00001\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\f\nApple Inc.1,0*\6\3U\4\v\f#Apple Worldwide Developer Relations1D0B\6\3U\4\3\f;Apple Worldwide Developer Relations Certification Authority0\30\23\r151113021509Z\23\r230207214847Z01705\6\3U\4\3\f.Mac App Store and iTunes Store Receipt Signing1,0*\6\3U\4\v\f#Apple Worldwide Developer Relations1\0190\17\6\3U\4\n\f\nApple Inc.1\v0\t\6\3U\4\6\19\2US0\1\"0\r\6\t*H\r\1\1\1\5\0\3\1\15\0000\1\n\2\1\1\0ρ%[և#3\28#&=ƟJ\rU\2ח9Tm}T\24,Rqd{ΉI\b崈q?[F.\29\3X\4>!x۷Ў\18L[*h7\30ҡ\fJXR\18\31\215-\18ʍHXxTk16\31J\6\fGT7}_J຤c+>o<R\26%\nv\14k[^sQI\bVC̎\2Р\\ii\16h&&9\29\16s\n]sv;-و\30\a&U\3I#\2\3\1\0\1\10\10?\6\b+\6\1\5\5\a\1\1\0043010/\6\b+\6\1\5\5\a0\1#http://ocsp.apple.com/ocsp03-wwdr040\29\6\3U\29\14\4\22\4\20vM6]+\40\f\6\3U\29\19\1\1\4\0020\0000\31\6\3U\29#\4\0240\22\20'\23\t\24`GYRT0\1\30\6\3U\29 \4\1\0210\1\0170\1\r\6\n*Hcd\5\6\00100\6\b+\6\1\5\5\a\2\0020\fReliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.06\6\b+\6\1\5\5\a\2\1\22*http://www.apple.com/certificateauthority/0\14\6\3U\29\15\1\1\4\4\3\2\a0\16\6\n*Hcd\6\v\1\4\2\5\0000\r\6\t*H\r\1\1\5\5\0\3\1\1\0\r\27.=[+\anBlC0_\\э\15\26%یÀY.\5\20\r۶5.|˭\23k\31wg\19^\25vZ c\15s\31eH\\(:\0167-\0049\31s\5\26**n+\1 \\}'3D۱Lgn\nO\6җkQZue\22\4b_\bhْ\0\0dX`|ui[*\29hnBL7\25;\28z\25CmH`\6\f6+\24\17-#Ўi\23\27{9GE0a/\190\4\"0\3\n\3\2\1\2\2\b\1޼9m\0160\r\6\t*H\r\1\1\5\5\0000b1\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\19\nApple Inc.1&0$\6\3U\4\v\19\29Apple Certification Authority1\0220\20\6\3U\4\3\19\rApple Root CA0\30\23\r130207214847Z\23\r230207214847Z01\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\f\nApple Inc.1,0*\6\3U\4\v\f#Apple Worldwide Developer Relations1D0B\6\3U\4\3\f;Apple Worldwide Developer Relations Certification Authority0\1\"0\r\6\t*H\r\1\1\1\5\0\3\1\15\0000\1\n\2\1\1\08TV$9H_&4Sz|cawd^\a#9P-\21VXp-~nJ>/ބ\26Wɯ{\24j\21\18I\21\b\25*2chR\21=k\24\3\1}\5g\147j\tgQd\\ѼWng5v6n8+\21N{%ZNғ\26q`3NU\18X\f\22\rwEPH+-䔅ĝhg~p\2YKwB9L;H!]jj\0225`F)Ëyjag\21hb_nϙ\27ce\2\3\1\0\100\29\6\3U\29\14\4\22\4\20'\23\t\24`GYRT0\15\6\3U\29\19\1\1\4\0050\3\1\10\31\6\3U\29#\4\0240\22\20+iGv\tk.@GM\b^0.\6\3U\29\31\4'0%0#!\31\29http://crl.apple.com/root.crl0\14\6\3U\29\15\1\1\4\4\3\2\10\16\6\n*Hcd\6\2\1\4\2\5\0000\r\6\t*H\r\1\1\5\5\0\3\1\1\0OY,l/\192\0055n}i\f\23w,gm:Y\\߃\1*arE0\r\29G񓊣tØr;>E\vT2\24Sk\nN\16\29Pl!\nNWk[<=\r#\29\vJ&?L\25\18\25mWzX{h䆌JI\20U\0K0ᠱ)\tw4\1\n;b\5cA\15;\29L۫ɕOM&)\1zf.!xၮӐ8\26g0\28Q\\ql\15\f\21\0310\40\3\3\2\1\2\2\1\0020\r\6\t*H\r\1\1\5\5\0000b1\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\19\nApple Inc.1&0$\6\3U\4\v\19\29Apple Certification Authority1\0220\20\6\3U\4\3\19\rApple Root CA0\30\23\r060425214036Z\23\r350209214036Z0b1\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\19\nApple Inc.1&0$\6\3U\4\v\19\29Apple Certification Authority1\0220\20\6\3U\4\3\19\rApple Root CA0\1\"0\r\6\t*H\r\1\1\1\5\0\3\1\15\0000\1\n\2\1\1\0䑩\t\31\30GP\5^y-6WLU\25Kl\a\"0\2\24>P\tAf$k\17У\27*\31z\fG[\02273\15M\20i\25r]\14_%\3UM]\rd5#\21K\21Y\29PXPg\b ˬ, op?\0010C\15=+I(\26ε\14^\28=:\15\14\0\v!\22.t<\rb\22qGSU/ApLE~\31LkPAtb\v\16A30XZ\0042h\29esg^eIv3\20ew-\2\3\1\0\1\1z0\1v0\14\6\3U\29\15\1\1\4\4\3\2\1\0060\15\6\3U\29\19\1\1\4\0050\3\1\10\29\6\3U\29\14\4\22\4\20+iGv\tk.@GM\b^0\31\6\3U\29#\4\0240\22\20+iGv\tk.@GM\b^0\1\17\6\3U\29 \4\1\b0\1\0040\1\0\6\t*Hcd\5\00100*\6\b+\6\1\5\5\a\2\1\22\30https://www.apple.com/appleca/0\6\b+\6\1\5\5\a\2\0020\26Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0\r\6\t*H\r\1\1\5\5\0\3\1\1\0\\6L-x팛wvw0O\31\27=G7@,Ա\18ؾsd\15yO4آ>xk\a}9S 8ıO\nk+Y\5\t|\23@V\17\30tӷ#;Go$ѷp\15E'mx\23\23~\"5%\15kԢ$#\17s`\27[\t/DH`8\21=&g 3j\r/Sj[dc3w:\a,V\15!\14ںs\25O6U٧2Bq~R\27B$\18*\15\29M^cK\23P\t\a7uu!1\10\1\2\1\001001\v0\t\6\3U\4\6\19\2US1\0190\17\6\3U\4\n\f\nApple Inc.1,0*\6\3U\4\v\f#Apple Worldwide Developer Relations1D0B\6\3U\4\3\f;Apple Worldwide Developer Relations Certification Authority\2\b\14W\t0\t\6\5+\14\3\2\26\5\0000\r\6\t*H\r\1\1\1\5\0\4\1\0\0!nnc\189w\1h?!R$$F\t\30\ayK\29vX7\27X;\3\5[|\1'u~-x4|/\14t#{\21й`+\v\0e^NSo!@9])+uS.oh7!䂅xy\vg\16m>:td#=d\23&\23.}\tUOg9\4:Z\6Xkwz'\27\20Xg\20F抂Or\1`?S\16ʧ:A\22dT>fAi\31M\26܇\5sY/Wt+

Even trying to send this string further on to Gamesparks will shut down the whole socket connection almost like a character/byte is a disconnect signal.
Edit: The escaped character: “\190” is shutting down the websocket :frowning:

Anyone has had this problem? We are really blocked by this problem at the moment.
Do we really have to UNESCAPE + BASE64 encode it back again to it’s rawformat to be able to send it for validation?

Is something trying to automatically decode the base64 version or is it something in Defold doing that? Maybe something in the implementation is outdated?

Have you tried to convert what you get to base64 before sending? https://github.com/britzl/desert/blob/master/desert/base64.lua

2 Likes

Me and @AGulev talked about receipt verification for iOS a year or so ago and I did some research. Receipt validation (which should take place on the backend) can be done towards the Apple provided receipt validation service (example: https://sandbox.itunes.apple.com/verifyReceipt) using HTTP POST. The post data would be:

local post_data = json.encode({
	["receipt-data"] = base64.encode(receipt),
	["password"] = "yourpasswordhere",
})

Have you tried to base64 encode the receipt before sending it to Gamesparks?

Would like to use Gamesparks validation of receipts as all the rest backend logic is there (and android as well) . Gamesparks might use the Apple service behind the scenes

Tried to base encode it but I think it then encoded all ‘’ as a char and not as C type escaped characters so I guess I need to unescape it first. Also that seem to be weird as it seems like normal lua escapes \xxx as octal values but Defold for some reason (that would be interesting to know) escapes \xxx with decimal values??
I guess it’s a big trial and error right now.

Sure, I’m not arguing against it.

I took a look at our IAP code and this is what we do:

if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
    lua_pushstring(L, "receipt");
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
        lua_pushlstring(L, (const char*) transaction.transactionReceipt.bytes, transaction.transactionReceipt.length);
    } else {
        NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
        lua_pushlstring(L, (const char*) receiptData.bytes, receiptData.length);
    }
    lua_rawset(L, -3);
}

The receipt is a binary data blob in ASN.1 format wrapped in a PKCS #7 container:

https://medium.com/revenuecat-blog/dissecting-an-app-store-receipt-b1e9c5136482

If you’re going to send it away to a Apple for validation you need to base64 encode it first:

If you are validating with Gamesparks it’s still going to get sent to Apple in the end for validation:

https://docs.gamesparks.com/api-documentation/request-api/store/iosbuygoodsrequest.html

The above link doesn’t mention anything about the format of the receipt string, perhaps you need to base64 encode it first? It crashed if you passed it the binary string right?

The receipt string that you pasted above consists of binary data. The string representation looks like it is escaped, but it really isn’t.

1 Like

First of all: Big thanks for your passionated support Britzl. It really helps AND gives a deeper insight of things.
So it’s solved.
I actually did try base64 encoding before and it didn’t work (used another lua implementation, also by Alex Kloss), it actually didnt work at all so I thought it was a deadend. Now when I tried the bases64.lua in Pkeod’s link above it worked!

So, the answer was quite simple in the end: Encode it into base64 before sending (just make sure to use an implementation such as: THIS ONE

Ones again, thank you guys! We are on our way to a great release!

6 Likes