How to know what AppleID/user did a purchase?

Hello,


I have a significant problem concerning the billing APIs.


My iOS app has its own user account handling so that the user can switch the device or have multiple devices with data in sync.


Now the user can purchase an auto renewing subscription which is (of course) implemented using the APIs of Apple.


The problem is the following situation:


  • User with AppleID X signs in with his account A.
  • He purchases the auto renewing subscription (obviously with AppleID X) while being logged into his account A. Now account A has the benefit of the subscription.
  • Now he uninstalls the app and reinstalls it.
  • He logs into another account B and restores the purchase. Now also account B has the benefit of the subscription.
  • How can I avoid this which is a major flaw? How can my server identify which AppleID is linked to which purchase?


A simple way would be to read out the UUID of the user but I know this is not allowed.


How can I fix this? Any help is highly appreciated!


Thanks in advance.

1) You can use the user's iCloud Account which is (usually) one-to-one associated with their iTunes Account. Write something to the user's key-value file in their iCloud Account that identifies them. There is also a way of identifying the user through a record in their provate space in CloudKit - but that's a bit more complicated.


2) You can use the device's keychain. Write something in the keychain of the device that identifies that device. The keychain is preserved when the app is deleted and reinstalled.

Thanks for the answer, but:


  1. How persistent is the keychain if not synced to iCloud?
  2. What if the user doen't use iCloud at all?
  3. What about multiple devices?

Let's be direct about this: The system is deliberately designed so that you DO NOT receive a unique identifier for the user's account.


If you have server based accounts, you should probably be storing the receipt information on your server instead of just storing a flag that says 'receipt verified'. And then consider doing some work to ensure that the same receipt doesn't show up on multiple accounts.


Just like you're presumably doing work to ensure that the same account isn't being used on a hundred devices at the same time.

How persistent is the keychain if not synced to iCloud?

It survives delete-and-reinstall of the app. Since you are storing "IAP purchased" in the keychain you don't care if it is wiped out by a restore-to-backup.


What if the user doen't use iCloud at all?

I think all users still have access to their iCloud key-value file.


What about multiple devices?

That's the choice above. The keychain is device specific; the iCloud is iTunes Account specific.


And if you are really into security the solution is to require that the user give you access to the CloudKit database, use the user's private database to identify the 'Apple ID' of the user as accessed from any device with that Apple ID, search the public database for originalTransaction_id's to identify repeats, record the originalTransaction_id in the public database after each purchase, and record any consumable quantities used in the user's private space as they get used (or use a date stamp system so a user can use a consumable without CloudKit access and don't allow consumables to be transferred if the date stamp is not current). It's very complicated.

Mhm, wouldn‘t it be enough to just store any originalTransactionId to the current user while he is ordering? In this moment, my server side validation runs and stores the new originalTransactionId to this user account. When he restores purchases while being logged in with another user account, I can check if the originalTransactionId of the purchase currently being validated is assigned to the user currently logged in. Is there‘s a mismatch I tell the user to switch to his other account and deny the validation. Should be working, no?

I believe what you are doing works well, provided the communication to your server is signed in some way so that it prevents a man-in-the-middle attack. The originalTransaction_id defines the user's account on iTunes. The need for additional security relates to a consumable IAP which can be consumed and inappropriately restored. "Consumed" is here equivalent to "expires" and there is no universal clock to measure "consumed" as accurately as "expired".


You are using your server as I proposed above to use CloudKit to detect the use of a duplicate originalTransaction_id. In your case you tell the user to log into their other account on your server. That message goes both to the legit user with two accounts on your server and to the illegit user who is trying to hack the system and steal the IAP using someone else's receipt. You have a server; I don't - I use CloudKit.


.

How to know what AppleID/user did a purchase?
 
 
Q