I plan to use non-renewing subscription on SaaS app since apple doesn't allow auto-renewable for SaaS.
Apple also requires us to provide a server side mechanism to track the subscription with multiple devices.
But, based on my research, apple also seems to reject app if registration is mandatory, so such user registration must be made optional.
My app can be used without registration at start, so registering is optional at this point. But, if users want to buy non-renewing subscription, registration is mandatory to track the subscription.
Does apple reject this approach?
Related links:
app rejected.how to track user non-renewing subscription
*UPDATE
I checked the session video of WWDC2012, and it seems it is ok to ask user to register with your server BEFORE purchase for non-renewing subs. I will post an answer once they really approved this method.
*UPDATE
I got an reply from apple through Resolution Center.
The bottom line is we should allow user to buy subscriptions without registration anyway.
This is the answer from apple review team.
It would be appropriate to make registration optional. You may provide
an alert stating that the user will not be able to track a
subscription on multiple devices without registering. However, you
should provide the option to register and track a subscription after
the subscription is purchased as well.
I don't have a definitive answer but my understanding (not just a guess) is that you must permit them to purchase the subscription without making an account. You can warn them that if they don't make an account, their subscription won't be portable to other devices, but you still have to let them move forward without an account if they want.
From a technical perspective, you could treat this as "you must allow the user to make an account without any personal information"; they might have an account on your server for receipt validation, etc, but it's not tied to their name, email, udid, etc. The issue is one of privacy, so as long as it's not personally identifiable info you're storing, it's fine to keep track of the subscription so you know when it expires, etc. (It's nice to later let them enter their email if they want so they can make the subscription portable.)
Of course, what Apple approves or not changes over time and varies for other reasons, so YMMV.
I would like to know how can I avoid having the user re-pay for an in-app subscription he already purchased.
Example: I purchase an App which offers in-app purchase on google play store for 5$ and now I shift from using an Android phone to an iPhone.
I came across this post which says it's not possible as they are two different competitors and would have to re-purchase the same app on the iOS once again, but is there a way to avoid it so that the end-user does not repay the sum of 5$ again?
I was thinking if it would be a good idea to have the receipt stored on a server and then when the user enters his email just do a lookup if there's a receipt associated with that email along with some validation logic.
In theory, I could avoid the user having to pay the 5$ with this approach but at the same time, I am not sure if doing this could get my app rejected or If this could lead to some different issues OR this is not doable at all and the user will have to end up paying 5$ anyways if he shifts from android to ios and vice versa.
The approach you suggested is correct. You would store the receipt on your server, along with the user identifier. Your server is responsible for refreshing the receipt with Apple/Google to keep the status up-to-date. You can then have an endpoint to your backend to check if a user is subscribed - regardless of the platform.
This is well within the App Store Guidelines, and is how large subscription businesses like Netflix and Spotify operate.
I'm referring to this question
Who bought my app
only with a little twist: I don't want to know the email address of the user or phone number or anything alike. All I care about is some unique identification of the user who purchased it (="the active android/ios account" that was billed).
Is that possible?
I want the user that bought the app on android to be able to access the app on ios. Also I want to prevent "frauds". Imagine somebody borrows my device with my android credentials and within the app logs into his account and presses "buy". That would enable the user to buy the app and it'd charge me. Also it would allow them to restore MY purchases. That's why I need to get the fingerprints of the user who bought it.
I am assuming you already have the account management facility in your app.
So answer to your second question would be to implement the register and login facility which would allow the users to log in with the fingerprint which is the separate problem.
So go ahead and solve this problem first.
The answer to your first question resides in the central server where you register and authenticate the users.
You will need to validate InApp purchase from your server.
The flow steps of how it should be done:
User clicks on the buy button. (It does not matter whether the original user is doing this action or a fraud)
Ask the user for authentication. In this case fingerprint. (The fraud would not be able to pass from this step.)
The app initiates the purchase flow. The user completes the flow.
The app receives the payment successful response from the google. (The app will not allow the access to the item to the user yet. The payment needs to be verified by our server. Google suggests we verify payment from the server and not the app. Refer to Security Best Practices.)
The app sends purchase receipt received from the Google + Unique Id(UserId, Email, Phone no.) to the server.
The server sends purchase receipt (purchaseToken) to Google for verification. The Google verifies it as a successful purchase.
Now that our server knows that the purchase was successful it creates an entry in the database with purchase info (Purchase time, Start time, Expiry time etc.) and user info.
(This is the answer to your first question)
The flow steps when the user logs in from the iOS or any other device.
The user logs in to the device.
The user tries to use the purchased product.
The app sends the request to the server.
The server checks whether the user has access to the resource.
Returns the response.
Key point is to have a Server which authenticates the user and verifies the purchase.
Follow my THIS answer you will get clear Idea on how to implement this.
I'm developing an app using Unity (for Android and iOS). I'm using the SOOMLA plugin to allow users to purchase Gems (virtual currency) with In App Purchase.
Users and Gems and all other game logic go through my server on Azure.
I want the following procedure to take place as a single transaction in some way:
User buys Gems with IAP
App notifies server
Server validates the purchase and updates data
But if the internet connection breaks down between step 1 and step 2 - the user payed for Gems that he did not receive (not good!)
So my current approach is this:
User initiates a purchase
App notifies the server
Server blindly updates data accordingly
User buys Gems with IAP
If the purchase is cancelled, notify server to undo it
That way, the user is guaranteed to get his purchased Gems, but I am not guaranteed to get paid (not great...)
Note: I don't want to manage user Gems in the store itself. I want everything on my own server. So the SOOMLA's balance is meaningless to me. I don't care for it.
I was thinking maybe the app can store the purchase data in persistent storage until it manages to notify the server about it, and then delete it. But I was also thinking that this might be a bad solution. Hence this question.
I imagine the best solution as something that will properly handle this scenario:
User buys Gems with IAP
IAP succeeds
Internet breaks down
My own server isn't notified
User uninstalls app from his device
User may then install the app on other devices:
Either he was charged and he got the gems by some magic
Or he was refunded automatically, since the gems were not received
So far it seems like this is impossible by any means, which makes me disappointed with the technology of IAP's. Hoping for answers that will prove me wrong.
Seems like all I'd ever need is the ability get a user's purchase history from my server, with a secured request to Google Play or Apple Store. But that's just not part of the framework.
So what are others doing? What is the best approach?
In general, you seem to suffer from the Two Generals' Problem which was
the first computer communication problem to be proved to be unsolvable.
Since everywhere in your communication protocol a message can be lost (even the acknowledgement or the acknowledgement`s acknowledgement or the ...) you cannot be 100% sure that both communication parties (the user device and your server) have agreed upon the same state. You can only say that upon a certain probability the state information has been interchanged successfully.
I would send a couple of ACKs back-and-forth and store the purchase if a sufficient number got trough. Quote from Wikipedia:
Also, the first general can send a marking on each message saying it is message 1, 2, 3 ... of n. This method will allow the second general to know how reliable the channel is and send an appropriate number of messages back to ensure a high probability of at least one message being received
For customer satisfaction I would take the odds in their favor - 1% not delivered goods will get you in a lot of trouble but 1% loss on your side is acceptable.
Considering your Gems are a virtual currency, then the natural in-app product type should be consumable, i.e. they are not restorable purchases.
To consume a purchase with a Google Play purchase you will call consumePurchase. On iOS you will call finishTransaction on the SKPaymentQueue. In both marketplaces the consumable purchase will remain in an active state until they have been consumed. If the user deletes the app off their device before the purchase is consumed, they will be able to re-install, and restore their previous unconsumed purchases.
In-between the initial purchase and consumption is where you want to put your server-side validation. When a purchase is made, send the receipt or token to your server, perform the validation and respond accordingly. The app should wait for a valid response from the server before consuming the purchase.
(Note that consumed purchases will not appear in the in_app collection on an iTunes receipt. They are only present if the purchase has not been consumed yet).
If the server is timing-out or network connectivity is lost the purchases will remain in an active state and the app should continue trying to send the details periodically until it receives a response it is expecting.
Purchases for both Google Play and iOS are stored locally so you will just need to run a process that looks for unconsumed purchases once network connectivity is re-established.
You can treat the provisioning of Gems in the same way a bank handles deposits of cheques; the new balance will be immediately updated but the amount spendable will not match until the cheque (or in your case a validation) is cleared.
Some pseudo code to make the process clear:
Purchase product or Restore purchases
While consumable purchases > 0
Send purchase receipt to API
If response is ok
If purchase is valid
Consume product
Allocate gems
Break
Else
Remove retroactive gem allocation
Discipline the naughty user
Break
Else
Retroactively allocate un-spendable gems
Pause process until network is re-established
Re-send receipt to API
I don't have much knowledge about android but after reading your post I was really interested to search keenly and more over how game like clash of clans in app purchase logic work and prevent freedom fake purchase hacks.
After doing some research I would like to share my thoughts over your problem, You can implement it by following approach:
Make your in app purchase verification completely online. For e.g., you can consider the game clash of clans.
How it works:
1)Game loads, synced with server. Network connection required, as network connection breaks game reloads from server.
2)User have 10 gems, server also have 10 gems.
3)User purchased gems, server verify purchase separately for the purchased consumables, gems credited to the users account.
4)If in can case network fails, then also server can verify purchase and later on it update it in account of user, whether it is on any device.
5)This will also help you to bypass many fake in app purchase hacks like freedom (prevention) and lucky patcher.
Google provide api for server side to verify or get purchase detail and when purchase from application side and server side match then only you credit gems or consumable item into users account.
For more information about in app purchases and their hack preventions you can visit these links:
1)Server side verification of in app purchase part 1 and part 2.
2)How would you verify in app purchase billing server side.
3)Verify purchase via PHP.
4)Secure in app purchase scenario on web server.
Hope this might lead you in direction which you want to go, also I would love to hear your thoughts over the same.
You can try restoring the In App purchases made with a particular account.
The feature is given just for this case when either the payment was made and user didn't receive the items he was promised or when he switched device.
Upon restoring the purchase you'll receive the purchased product again from the iTunes server and then you can accordingly notify your server.
Some advice:
User buys Gems with IAP
IAP succeeds
Internet breaks down
My own server isn't notified
User uninstalls app from his device
User may then install the app on other devices:
Either he was charged and he got the gems by some magic, or he was refunded automatically, since the gems were not received.
At step 3, receipt information is stored on the user's device. If the user uninstalls and reinstalls your app, the receipt information will be lost. But you can restore it; Apple talk about that here. You can resend a restored receipt to your server. At your server, you verify that plus Gems for the user so he can receive what he should be.
he was refunded automatically, since the gems were not received
This seem impossible with IAP because Apple does not allow a user to cancel their purchase. (With Google IAB, refund are allowed, more about that here)
I'm using version 3 of the in-app billing API. I have a single, managed, non-consumable item. I have not released this feature in my app yet, so I want to decide on the purchase payload contents before there are any purchases.
From "Security Best Practices":
Set the developer payload string when making purchase requests
With the In-app Billing Version 3 API, you can include a 'developer
payload' string token when sending your purchase request to Google
Play. Typically, this is used to pass in a string token that uniquely
identifies this purchase request. If you specify a string value,
Google Play returns this string along with the purchase response.
Subsequently, when you make queries about this purchase, Google Play
returns this string together with the purchase details.
You should pass in a string token that helps your application to
identify the user who made the purchase, so that you can later verify
that this is a legitimate purchase by that user. For consumable items,
you can use a randomly generated string, but for non-consumable items
you should use a string that uniquely identifies the user.
When you get back the response from Google Play, make sure to verify
that the developer payload string matches the token that you sent
previously with the purchase request. As a further security
precaution, you should perform the verification on your own secure
server.
Rightly or wrongly, I have decided not to take the "further security precaution" of setting up a server to perform purchase verification. And I do not store my own record of the purchase -- I always call the billing API. So is there really any reason for me to do this payload verification? The verification API itself certainly verifies the identity of a user before reporting an item as purchased, and if an attacker has compromised a device (either the app or the google play API), I don't see any benefit of doing an additional check on the user's identify on the device where it can easily be circumvented. Or is there a reason to do this that I'm not thinking of?
If you don't keep a record there is no way to verify that what you get is what you sent. So if you add something to the developer payload, you can either trust that it is legitimate (which is a reasonable assumption if the signature verifies), or not trust it completely and only use it a reference, but not for validating license status, etc. If you store the user email, for example, you can use the value instead of asking them to enter it again, which is slightly more user friendly, but your app won't break if it is not there.
Personally, I think that this whole 'best practices' part is confusing and is trying to make you do work that the API should really be doing. Since the purchase is tied to a Google account, and the Play Store obviously saves this information, they should just give you this in the purchase details. Getting a proper user ID requires additional permissions that you shouldn't need to add just to cover for the deficiencies of the IAB API.
So, in short, unless you have your own server and special add-on logic, just don't use the developer payload. You should be OK, as long as the IAB v3 API works (which is, unfortunately, quite a big 'if' at this point).
You should pass in a string token that helps your application to identify the user who made the purchase...
If your application provides its own user login and identity, which is different from what Google accounts the phone is connected to, then you would need to use the developer payload to attach the purchase to one of your accounts that made the purchase. Otherwise someone could switch accounts in your app, and get the benefit of purchased stuff.
e.g.
Suppose our app has login for userA and userB. And the phone's Android google account is X.
userA, logs into our app and purchases life membership. The purchase details are stored under google account X.
userA logs out, and userB logs into our app. Now, userB also gets the benefit of life membership, as android google account is still X.
To avoid such misuse, we will tie a purchase to an account. In the above example, we will set developer payload as "userA" when userA is making the purchase. So when userB signs in, the payload won't match to signed in user (userB), and we will ignore the purchase. Thus userB can't get benefits of a purchase done by userA.
There is also another approach to the developer payload handling. As Nikolay Elenkov said it is too much overhead to require user ID and setting additional permissions for user profile to your app, so this is not a good approach. So let's see what Google says in the latest version of TrivialDrive sample app in In-App Billing v3 samples:
WARNING: Locally generating a random string when starting a purchase and
verifying it here might seem like a good approach, but this will fail in the
case where the user purchases an item on one device and then uses your app on
a different device, because on the other device you will not have access to the
random string you originally generated.
So the random string is not a good idea if you are going to verify the purchased item on another device, but still they don't say this is not a good idea for verifying the purchase response.
I would say - use developer payload only for verifying the purchase by sending a random unique string, save it in preferences/database and on the purchase response check this developer payload. As for querying the inventory (in-app purchases) on Activity start - don't bother checking developer payload since that might happen on another device where you don't have that random unique string stored. That's how I see it.
It depends how you verify the developerPayload. There are two scenarios: remote verification (using server) and local (on device).
Server
If you're using a server for developerPayload verification it can be arbitrary string that can be easily computed on both the device and server. You should be able to identify the user who has performed the request. Assuming every user has the corresponding accountId, the developerPayload may be computed as combination with purchaseId (SKU name) like this:
MD5(purchaseId + accountId)
Device
developerPayload shouldn't be user email. A good example why you shouldn't use email as payload is Google for Work service. Users are able to change their email associated with the account. The only constant thing is accountId. In most cases email will be OK (e.g. Gmail addresses are immutable at the moment), but remember to design for future.
Multiple users may use the same device, so you must be able to distinguish who's the owner of the item. For device verification developerPayload is a string that uniquely identifies the user e.g.:
MD5(purchaseId + accountId)
Conclusion
Generally the developerPayload in both cases may be just the accountId. For me it looks like security through obscurity. The MD5 (or other hashing algorithm) and purchaseId is just a way to make the payload more random without explicitly showing that we're using id of the account. The attacker would have to decompile the app to check how it is computed. If the app is obfuscated even better for you.
The payload doesn't provide any security. It can be easily spoofed with 'device' approach and without any effort seized in 'server' checking. Remember to implement signature checking using your public key available in the Google Publisher account console.
*A must-read blog post about using account id instead of email.
In the Google IO video about IAB v3 given by the author of the trivial drive sample himself, this was briefly addressed towards the end of the video. It's to prevent replay attacks, e.g. attacker sniffs the traffic, steals the packet containing a successful purchase, then tries to replay the packet on his own device. If your app doesn't check the identity of the buyer via the dev payload (ideally on your server) before releasing the premium content (also ideally from your server), the attacker will succeed. Signature verification can't detect this since the packet is intact.
In my opinion, this protection seems ideal for apps with online account connectivity like clash of clans (payload comes in naturally since you have to identify users anyway), especially where hacking compromises multiplayer gameplay with far reaching effects other than a simple localized case of piracy. In contrast, if client side hacks on the apk can already unlock the premium content then this protection is not very useful.
(If the attacker attempts to spoof the payload, the signature verification should fail).
Late 2018 update: The official Google Play Billing Library intentionally does not expose the developerPayload. From here:
The field developerPayload is a legacy field, kept to maintain the compatibility with old implementations, but as mentioned on Purchasing In-app Billing Products page (https://developer.android.com/training/in-app-billing/purchase-iab-products.html), this field isn't always available when completing tasks related to In-app Billing.
And since the library was designed to represent the most updated development model, we decided to don't support developerPayload in our implementation and we have no plans to include this field into the library.
If you rely any important implementation of your in-app billing logic on the developerPayload, we recommend you change this approach, because this field will be deprecated at some point (or soon).
The recommended approaches is to use your own backend to validate and track important details about your orders. For more details, check the Security and Design page (https://developer.android.com/google/play/billing/billing_best_practices.html).
I struggled with this one. Since a Google Play account can only own one of any "managed" item, but could have several devices (I have three), the above comment from somebody that you sell a "per device" won't work... they'd be able to put it on their first device, and no others ever... If you buy a premium upgrade, it should work on all your phones/tablets.
I despise the notion of getting the user's email address, but I really found no other reliable method. So I grab the 1st account that matches "google.com" in the accounts list (yep, a permission to add to your manifest), and then immediately hash it so it's no longer usable as an email address but does provide a "unique enough" token. That's what I send as the Developer Payload. Since most people activate their device with their Google Play id, there's a good shot all three devices will get the same token (using the same hash algorithm on each device).
It even works on KitKat with multiple "users". (My developer id is on one user, my test id on another, and each user in their own sandbox).
I've tested it across six devices with a total of 3 users and each users devices have returned the same hash, and the different users all have distinct hashes, satisfying the guidelines.
At no point am I storing the user's email address, it's passed straight from the code to get the account names to the hash function and only the hash is saved in the heap.
There's probably still a better solution out there that respects users privacy even more, but so far I haven't found it. I'll be putting a very clear description of how I use the users Email address in my privacy policy once the app is published.
This often responds to a product definition (Your application).
For example for the case of subscriptions. Will the same user be able to use the subscription on all the devices he / she has? If the answer is yes. We did not check the payload.
For consumables. Suppose a purchase in your application gives you 10 virtual coins. Will the user be able to use these coins on different devices? 4 on one device and 6 on another?
If we want to work only on the device that made the purchase we have to check the payload for example with a self-generated string and locallly stored.
Based on these questions we have to decide how to implement payload check.
Regards
Santiago