19

We have issues fully understanding the receipt validation flow in iOS.

Here is what we currently do (in development):

In applicationDidFinishLaunching and in applicationWillEnterForeground we validate the receipt on the server side, if there is no receipt or the receipt is invalid, we try to refresh the receipt and revalidate it.

Here are some issues/questions:

  1. What are the cases where there is no receipt available on the device ?

  2. Should we always issue a receipt refresh request when there is no receipt ?

  3. Why is this alert box sometimes shown on startup ? I understand this is shown on a receipt refresh request ?

Sign in required?

  1. When should a receipt verification happen ? We currently do it whenever a purchase is made to verify the purchase, is this correct usage ?
the_critic
  • 12,720
  • 19
  • 67
  • 115

4 Answers4

13
  1. In production a receipt is always available on device. In test after the first install there is not. So if you want to do a correct test, you must restore a purchase even if it doesn't exist a purchase on that user in the test environment. Why is that? App downloaded from the appstore always comes with a receipt even if they are free.
  2. Depends on the business logic you want to apply. If you are validating the receipt against a server each time the use launch the app, of course you need the receipt. If it is not present (but in production is always) or not valid, you can ask for a refresh or restore, but as far as I remember you should always ask the user first if he/she want to do that (can be a reason for reject). Restore and Refresh are not the same thing.
  3. This usually appear in purchase/restor/refresh. But also If the account has some pending requests because the app has crashed or you interrupted the debugging before the request end somehow, you will be bored by a lot of that. There is no way to flush them programmatically, just login until they stop. Of course it will not be a valid test.
  4. It's up to you and about the kind of purchase. If it is an autorenewable subscription, you can validate the receipt against a server, then store the the "end date" on the client and make another check after the date is expired. Pay attention that receipts can be quite big, because the have also all history values.
Andrea
  • 26,120
  • 10
  • 85
  • 131
  • 1
    I think that's a pretty solid answer, thank you. So, if we are not as strict as to verify the receipt on startup, would after each purchase be a good point to do it ? We also don't want to run into point 2.) you mentioned. So the flow would be: 1) User purchases subscription. 2) Verify receipt 3) Verificaion Succeeded: Schedule a local notification for expiration date (Is this a safe method ?). 4) Receipt expiration notification fired -> Revalidate or Lock premium features. Does that seem like a good way of handling this ? – the_critic Dec 08 '15 at 19:06
  • 1
    I really depends on the kind of purchase. If is not a subscription a validation right after the purchase sounds ok for me. If it is a subscription you must know the end of it, thus the flow you presented its fine except for the local notification. Let's suppose that you are buying a monthly auto renewable subscription, each month if the user doesn't stop the auto renew mechanism, the subscription is automatically renewed. I've tried to understand when this happen without success, probably few days before the real expire date. – Andrea Dec 09 '15 at 08:32
  • Automatically means that you do not need to do nothing. I would save locally (keychain) the expire day, when I'm around that date I would send the receipt again for validation, until is expired or updated. If the validation sees a new month I update the date, if the receipt is expired I would present an alert like "your subscription seems to be expired $end date$ would you like to try a refresh"? You can send the receipt to your validation server all the times you want without asking the user, but you can't refresh or restore without asking the user. – Andrea Dec 09 '15 at 08:32
  • Can you please give me suggestion about this? https://stackoverflow.com/questions/47712225/auto-renewable-subscription-wrong-time-response-sandbox-mode – Siddharth Dec 09 '17 at 09:12
2
  1. As Zhang mentioned, if there is no purchase or restore took place, there will be no receipt in the store
  2. Locate the receipt. If no receipt is found, then the validation fails and you should not request receipt refresh again. Only when you will restore process by yourself, you should request for the receipt again.
  3. This will be shown always when you will try to refresh the receipt (or you will pick from settings that you want not to ask for a password for 15 minutes).
  4. Yes.

For more information, look here: https://www.objc.io/issues/17-security/receipt-validation/#about-validation

m.aibin
  • 3,528
  • 4
  • 28
  • 47
1

If a user downloaded the app from the App Store – yes, receipt always exists.

However, in sandbox if your app was installed via Xcode or Testflight, then there won’t be a receipt until you make a purchase or restore.

Take a look at this complete FAQ about receipt validation in our blog:

https://blog.apphud.com/receipt-validation/

apphud
  • 625
  • 4
  • 8
0

1.No purchase/Restore took place.
2.Nope.See 1
4.Sure.For consumable products,remember to save hash on your server,in order to defeat replay attack.

Zhang HanSheng
  • 342
  • 1
  • 13
  • I don't really understand here. The validation receipt is to check this is a valid transaction or not, right? So after the transaction state is `.Purchased`, i call to validate receipt to verify the order. And if the receipt is invalid, mark that trasaction is fraud, right? – TomSawyer May 17 '16 at 11:25