My app provides extra content in its inapp store (non-consumables). The products (external files) are all stored on my server, so I can dynamically add new. Once the user has bought an item, my server verifies it and remembers the transaction data.
How can I now deliver my content? Let's say the user buys it, exits the app, and comes back later to display the content. Since the data is on the server, my app now needs to query the server once again to get the content. How can the server verify that the client making the query is a valid buyer of the content? Should I save something (like the transaction ID) on the app and then verify through this? Or are there better approaches?
I chose to save the transaction ID and transaction date of a bought product on the local device. The server verifies through this. The ID and date are stored in the keychain, to give them some protection from being read by a 3rd party.
If someone has better suggestions, he/she can still post it.
Related
Implementing subscriptions on an iOS app means we want to handle SSEs in case of subscription status change, as to manage the user's rights inside the service.
The Apple documentation doesn't show an explicit customer GUID.
They provide, in each SSE's payload, receipts, e.g. the latest one.
The question is: how can an API server uniquely identify customers?
Should the API server keep track of every receipt, in an inheritance way?
I.e. should the API persist every receipt, and a link to the previous receipt, up to the first
one that was emitted (which can be linked to a customer through the iOS app the user used to initiate its subscription), and re-trace this history on every SSE?
Per this thread, the applicationUsername service-side UUID (used by apple, for "irregular activity checking") isn't a solution, as it isn't provided in receipts or SSEs. The thread hints that using the transaction IDs is still the best way to identify a SSE, as it is ultimately tied to a user, and it is up to the service to keep track of transactions made by the user on the Apple platform for the given service.
Isn't there an easier, more direct, way, to establish the relationship between a SSE, its apple customer, and the service's user?
After digging for a while and asking around, I reached the following conclusion:
There is only one way to tie a transaction event to a user, and that is by the
restoration mechanism one has to implement on their application.
For this reason, you need to at least keep track of original transaction IDs,
so when the restoration mechanism is triggered on your app, you can check the
currently logged user on your app, and call your back-end with the logged user,
and a list of original transaction IDs.
Usually, when a user subscribes, it is mainly done from within your app, so you
can do this link in a trivial way.
But, because you can "re-subscribe" from the AppStore after a while, without
going through your app, Apple may send a SSE to your back-end which would contain
a new (hence unknown) original transaction ID, since this new subscription is
has a new transaction.
In short,
You need to keep at least a DB of original transaction IDs you receive as SSEs
You need to implement the restoration mechanism as to contact your server every
time the app starts, with the list of transaction IDs / original transaction IDs Apple gives you
You need to accept having transactions stored in your backend without a link
to a user (because the user may have re-subscribed without launching the app yet)
When building In App Purchases into an iOS app, Apple gives you access to a receipt that you can send to your server to view all In App Purchase transactions for that given iTunes user related to your application.
If in my application I require users to login or create an account through my system before making a purchase, how can I guarantee that iTunes receipt will not be duplicated?
For example, if a user makes a purchase, the application sends the user ID, and iTunes receipt to my server. The server then stores that receipt along with the user ID in a database. The next time the server wants to check the users purchases we can retrieve all the receipts for that given user ID out of the database and run checks on it.
But if the user logs out and logs in as a different user and makes another purchase the receipt will be sent to the server again, with a different user ID. Effectively, allowing 1 purchase to be used on unlimited user accounts.
Due to the fact that the receipts change over time (auto renewing subscriptions, etc), I don't think it's safe to rely on the receipt being the same every time it's sent to my server and using the receipt data as a unique identifier.
I also considered storing the original_transaction_id for one of the transactions, but I don't think that would work since an application might have multiple non-consumable items, or multiple subscriptions, therefor there might be multiple completely valid original_transaction_id's in one receipt. So it doesn't really associate that receipt, but just the transaction.
Ideally, I'd like a system where when a user logs out, and logs in (as a different user or same), the application will send the receipt to the server, and dissociate any of the same receipts for all existing users, and link this new receipt to the user that logged in. Problem is, it doesn't look like there is any type of unique identifier for a given receipt that I can use to check for duplicate receipts in my system.
What is the best way to detect duplicate receipts sent to my server (so I can dissociate the old receipts accordingly)?
PS. I think this system is most important for subscriptions, and non-consumable items. For consumable items it will always have to be linked to 1 specific user, and I can just store the transaction_id and original_transaction_id for that consumable item to ensure it doesn't get duplicated.
Hello I am currently trying to take advantage of the Subscription Status URL that iTunes connect gives you to get updates on a auto renewable in app subscription.
I have my endpoint up and running, and I am getting all the receipt info I need and the status of the update, however I have no current way of tying this update back to a specific user of my application.
For example, every user of my app has a UUID, and in a perfect world I would somehow like to tell Apple during a purchase which user uuid purchased this subscription and then get that UUID back in the POST request from the Subscription Status URL.
Is this possible?
You have identified what I consider to be one of the biggest flaws in StoreKit, that the receipt does not contain a way to identify the user (iTunes account in this case).
The way around this is: When your users make a purchase and your app processes a transaction, you need to post the transaction identifier (and probably the receipt data) to your backend and associate it with your user's backend record. Then when you get a push from Apple, you can look up the user it relates to by transaction id.
This is not an ideal solution, since different app users can be sharing a receipt via the same iTunes account and other edge cases like that, buts it is a good as you can do with the way app receipts work.
The way my app works is, I have users that have registered with me and they can log in and buy coins. The coins are in-app purchases using StoreKit.
The way I validate receipts is by sending them to my server. Along with the receipt, I send along the player's userid so my server knows who to credit.
Here is the problem. Lets say the transaction fails. When the app tries to do validation again, I will not know which user bought this.
Is there some way to add some metadata to a transaction so I can later know which user account bought it?
Thanks
As far as I know you can't add info to a SKTransaction.
What I usually do is a queue of unverified transactions. That queue usually has objects that have all the information needed by your server (your player id), the transaction itself, and its state (does the transaction has been completed, for instance?)
I try to dispatch that queue every time the app connects, and if it fails more than X times then I prompt a pop-up asking for the user to send an email with the details of the issue.
i am implementing in app purchases into a iOS application. I am using the server model (so all the in app items are stored on my server). The purchase model works like this:
user buys a item in the application
application sends the receipt-data to my server (receipt-data is a digitally signed chunk of data)
the server then sends a verification to the apple server
if the verification is successful the server returns data about the transaction
I've been searching through the documentation but i cant answer this questions:
can i validate that the receipt-data came from the apple store (checking the signiture or do i have to come up with a mechanism for that)?
if a user buys a item that was removed from the store (due to an old cache) can i reject the purchase?
If anyone has any experience with this i would appreciate the help.
You can validate the receipt-data come from the apple store by following Local validation.
If user buy a removed item. It's mean product_id does not exist in Itune. Transaction will be fail. You should update Product Request, when user use IAP.