Preventing Trial Period Fraudulent in iOS In App purchases - ios

We have a app with a auto renewable IAP for which we offer a initial trial period to the user and charge once the trial period has expired. Our app maintains user account management(user login) and all features (including the IAP) are accessible only when the user is logged in.
There are two scenarios to consider:
Case 1: A new user(app user) opts to purchase the subscription for trial period on a device where she's logged in with her apple id. She later(post expiry of the trial period) installs the app on another device and signs up with a different app account but uses the same Apple Id. Since Apple Ids are opaque to the app, the app has no way to know that this user has already purchased trial, so the app UI presents them an option to start with a trial period. Since the Apple Id used is same, the user will be charged.
Although, this scenario is rare and can be justified on the pretext that the same Apple Id is used so the user is supposed to be charged, but it is fallacious on part of the app to suggest that trial period is available for the new app user(different login id)
Also, the user might not be intentionally doing it to avail a second trial period, but might have forgotten about the previous purchase and may use an alternate email next time they sign up.
How do you prevent the user to be charged if they have already used up the trial for the same Apple ID, or if there's a way to know if the current user(Apple ID user) has already made this purchase in the past, so that you do not show them trial option anymore. Would restore purchases help in that regard?
Case 2: The same app user may intentionally change the apple id on the new/same device to avail multiple trials. While your app will detect the user has already purchased the trial, you may choose to let the user not show the subscription purchasing UI but if you do the purchase workflow on part of Apple would still consider it to be trial period(new apple id) and not remit you the payment for the same.
How do you circumvent these conditions or if there's a flaw in my understanding where these situations would not occur at all.
For case 1: maybe the following may work, but not sure:
Whenever there's a new login to the app, the app should either refresh receipt or ask to restore transactions to the user(this can be frustrating for actual first time users) and the receipt validation should be performed to check if the user had previous purchase and if the transaction id is linked to some previous user. This is basically a kind of self managed restore. But still in this case, the new user will not be able to get the trial period, you can just prompt that the current apple id is already used for trial.
Please suggest if my understanding is correct.

Related

iOS & Firebase Auto-renewable Subscriptions

My problem:
I am having a hard time figuring out a way to safely manage auto-renewable subscriptions in iOS with Firebase.
Purchase process:
User1 purchases a subscription
Update User1's account on Firebase w/ the subscription identifier
(used to unlock content)
Store original_transaciton_identifier(OTI) w/ uid of User1 to match w/ receipt verification from Apple.
Grant user access
Edge cases causing my brain to implode:
User1 logs out of AppleId used to purchase subscription, but remains logged in to app w/ Firestore credentials.
Therefore, when I go to verify if the subscription has expired it does not return a valid subscription. I want the user to be able to keep their access until it is expired or canceled. Any tips on achieving this?
User2 logs into the same device User1 was previously using.
Therefore, the same AppleId is being used for both users. I can check if the current user has a subscription, and check the OTI to see if it corresponds to User2...which it won't.
We will show the 'purchase iAPs' screen, but what if this user wants to buy a subscription as well under the same AppleId? Is it normal for me to handle this saying, "Apple Id already connected with another account or something"?
Relevant articles I've been able to find:
How to tie auto-renewable subscriptions to in house user, not appled id
I've been struggling with this for sometime and haven't been able to find many resources. All help is appreciated.
For case #1:
When you attempt to access the receipt Apple will trigger a login prompt for the user to enter their iTunes credentials. If a receipt is still unavailable, you won't be able to verify the subscription status. The "right" way to do this is to store the entire receipt on your server, and periodically refresh it with /verifyReceipt. You'll check if the subscription was cancelled, and update the expiration_date so you know when to cut off access for the user.
For case #2:
Is it normal for me to handle this saying, "Apple Id already connected
with another account or something"?
Yes! If you're able to look at how some other large subscription apps handle this (Netflix, Spotify, HBO, etc.) - it's similar to what you describe. Instead of checking the receipt locally every time, if you maintain the subscription status on your server (as mentioned in #1) this would only happen if the user tries to "Restore Purchases".
This is a pretty extreme edge case, since not many people try to make a purchase on their friends phone and would require TouchID/FaceID in most cases - so it's more of a fraud prevention feature. Once you get millions of users you can get fancy and send them an automated email link to signup with Stripe if you detect this.
Alternative:
RevenueCat can handle all the subscription tracking and these edge cases out-of-the-box, and it plays nice with an official Firebase integration. Disclaimer: I work there.

How do apps tie accounts with in-app purchase subscription?

I'm working on an iOS app where a user must sign up/sign in to an account for my app. To be able to use my services I want users to pay via in-app purchases (auto-renewing in my case). This would then tie their IAP to their account (they created with us) to be able to use on any other iOS device.
Case 1:
For example if a subscription was bought on phone A for an account, when signing on to phone B (using the same account) shouldn't make the user pay again.
Case 2:
Or if a subscription was bought for account A on a phone, when signing up for account B on the same phone should make the user pay for account B.
Basically I want an in-app purchase to tie to my account (rather than a apple device/Apple account which is how it works to my understanding.)
I understand that their are receipts which is probably part of the answer to my question. Or if this a limitation to in app purchases what other ways can this be done (other than using Apple's IAP)
The answer to the title of the question:
When a purchase is made there is an update received in the app, the next time it is launched which contains a transaction_id (original_transaction_id for renewals), you should associate this transaction id with your app user id.
Case 1: Apple provides an option to "Restore Purchases" in your app. Since, the same account is used, your app servers would already know that a user has already paid and the app shouldn't prompt the user to pay again. However, in order to receive the upcoming renewal updates on phone B, you must "Restore Purchases" which would let Apple link the previous purchase on this device as well. Once the restore is done, the users purchase receipt will be available on the device and all subsequent actions should be taken based on the content validation of the receipt.
Few points here:
Apple will reject your app, if it doesn't provide this option to the user.
Even if your app is buggy, and you failed to restore purchases, user wouldn't be charged again. The purchase would fail saying you already have purchased this.
The above case is completely based on the assumption that the user is using the same Apple Id on both the devices(same application user id doesn't matter).
Case 2: I am not sure if that is anyhow possible. Since it's the same device, the user uses the same AppleId(unless he signs out and changes apple id in App Store) and Apple will restrict the repurchase. At best you may restrict the account B with the subscription content but if your application allows multiple accounts on the same device use case(e.g Instagram), I am not sure if there's a provision for the same.
I tested the same scenario for a music service app I use. Have an active subscription, logged out and signed up with other email (app), but the purchase was denied alerting I have already purchased. However, it was allowing me upgrade and downgrade options. I didn't opt for testing them so not to mess up my account.
P.S: There are a lot of other caveats/gotchas to take care of. Some of them:
In case 2, apple restricts the repurchase but it doesn't restrict if the user chooses an option other than the current active subscription, which will upgrade/ downgrade the subscription. Based on how you have implemented things, it might even change the subscription for user A immediately or next time the user logs back in or on next renewal thereafter.
In both the cases discussed here, user uses the same Apple Id, but consider the cases - same Apple Id different app id AND different Apple Id and same app Id. (See this)
For case 2, you should always refresh receipts or restore purchases(if there's no receipt available) for a fresh user login. The receipt has a original transaction id which you should have linked the first time the purchase was made with user A. Based on the receipt, you can either choose to let user B access the content or restrict. However, you cannot let the user pay for the new account(I suppose so).
Helpful Links:
Restoring Purchases
Receipt Validation

Apple In-App Purchase: How apple use the applicationusername to Detecting Irregular Activity?

In apple's document, it says developer can use the applicationusername to Detecting Irregular Activity,but i don't know how to use it.The document just says hash a userId,but how can i detect the irrgular activity? Does the apple's server have a server API to notify me ?
Here the link:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/RequestPayment.html#//apple_ref/doc/uid/TP40008267-CH4-SW6
Let's day your app uses an account system so each user has an identifier (email, username etc) which we refer as appId here and the app store login as appleId
Scenario:
Say user purchased a subscription with a trial period (txn123) with appId usr123 having appleId appl123
Later she unsubscribed the subscription.
After few months she changed the AppleID for some reason.
Again she wants to purchase the subscription.
She will login into the app using same appId, usr123.
As she already has used trial with that appId, your app will recognise her, and will show buy button to her.
When she will click on the Buy button, Apple UI will show that she is eligible for Trial, and will be charged after 7 days.
If you had passed the applicationUserName field in the payment(payment object) in the both the transaction user makes, apple will recognise that and may take a remedial action (like actually charging the user instead of offering a second trial period).
At this point I am not sure, how Apple is going to inform your app/ecosystem about this irregular activity. I have not tested this scenario myself as yet, will update the answer once I have done so.
Several things may happen:
Apple declines the second purchase because it detects the irregular activity of the same user purchasing the trial period again. But how would Apple know if the user is intentionally trying to make the purchase now after trial has expired. Anyways, apple can say that this user seems to be associated with some other apple id also which has made a purchase in the past, thus not allowing the transaction with the pair.
Apple may actually charge the user, since they are trying to buy after a trial but in this case Apple will be offering a Apple Id user without a trial period in their name.
Apple may allow the transaction with trial period offering and may resolve this through other/offline channel.

iOS App rejected due to wrong purchase type

I am stuck with one of the in-app purchase rejection issue in my app and need some help on this.
What this in-app for?
In our app we have options for user to become premium user. A user can become premium user to enjoy some benefits and it is tied to time. There are two in-app products which defines them
One month premium service.
One year premium service.
Since these are time based service, user expects these service should be made available for that user once he/she purchase the product for the specified time, from all his/her other devices. In order to track whether the user is premium service user or not, once the purchase is done, the app writes a entry in server about premium service. So when user uses other device and logs in, he/she can enjoy the premium service without any issues. For this reason I created the above mentioned products as "consumable", thinking that it is controlled by our server there will be no issues. But apple came back with rejection and asked me to change the products to "non-renewing subscription".
Here is what apple says about this
We found that the Purchasability Type for one or more of your In App Purchase products was inappropriately set, which is not in compliance with the App Store Review Guidelines.
"Premium account service for 1 month and 1 year" IAPs are set to Consumable.
However, based on product functionality, it would be more appropriate to use the Non-Renewable Subscription In App Purchase type because the service offered by your application requires the user to make an advance payment to access the content or receive the service.
The Purchasability type cannot be changed once an In App Purchase product has been created. Therefore, you will need to create a new In App Purchase product with the correct Purchasability Type. To create a new In App Purchase in iTunes Connect, go to Manage Your In App Purchases, select your app, and click "Create New". The current product will show in iTunes Connect as "Rejected".
Non-Renewable Subscription content must be made available to all iOS devices owned by a single user, as indicated in Guideline 11.6 of the App Store Review Guidelines:
11.6 Content subscriptions using IAP must last a minimum of 7 days and be available to the user from all of their iOS devices
If you choose to use user registration to meet this requirement, please keep in mind that it is not appropriate to require user registration. Such user registration must be made optional. It would be appropriate to make it clear to the user that only by registering will they be able to access the content from all of their iOS devices; and to provide them a way to register later, if they wish to access the content on their other iOS devices at a future time.
For more information about Purchasability Type, please to refer to the iTunes Connect Developer Guide.
Now I have created new in-app products which are non-renewing. But this works the same way as I mentioned earlier, i.e. the server keeps track of whether user is premium user or not, expiry date. When user goes to other device and does login, the app comes to know whether user is premium or not and based on that app works.
But I have couple of questions on this,
Should I need to provide the "Restore" button in the app? If so what is the purpose and how it works?
Since the user can access this service only after doing login to the app (it is different from app store account). Will these two logins make any issue?
Please share your valuable inputs.
It is highly unlikely that the user will end up in a situation where they won't be able to use your app unless they restore their purchases, however it is still possible. Imagine your server goes down for a day and during that day some user purchases a subscription, gets a new iPhone, installs your app on the new device and then wipes their old iPhone. I can think of a couple of other, equally unlikely, but still possible situations (Apple receipt validation server going down, etc) in which the purchase receipt will get lost in transit. It's best to provide the button, and if Apple thinks that you need it in your app, you will have a hard time convincing them otherwise.
If by "two logins" you mean user having to log in to your system and then log in to the App Store to purchase the subscription, that should not be a problem.
I recommend you make the changes Apple requested to the Purchasability Type and then re-submit. If you need to clarify a lack of a restore button put it in the notes for the reviewer

switching from auto-renewable to renewable subscription

My client has an app in the App Store that uses the auto-renew subscription type. Upon resubmitting the app it was rejected because they claimed they don't have periodic content (even though they do... but this problem seems to be ubiquitous currently). I was wondering what the best approach is to deal with non-renewing subscriptions. Specifically issues dealing with:
Losing your device and restoring your subscription
Restoring your subscription to multiple devices (as mandated by Apple)
Preventing users from abusing the system.
What I came up with so far is the following:
When a user purchases a 1 month subscription this information is stored locally (say in NSUserDefaults). Also, a unique ID is generated and sent to my clients server. When the subscription ends users are asked whether they want to be directed to the purchase screen. If users wishes to save the subscription in case they need to restore they device, or in case they lose their device, they can opt to have the unique identifier sent to their email address (which they are prompted to enter, indicating that this information will not be used). The app has an place to enter this ID. It will retrieve the subscription information from the server and again store this in the NSUserDefaults. Each time a restore is done, a counter is increased. When it has reached say 5, the user can no longer restore. The same principle described above works in the case of sharing subscriptions over multiple devices. Does this seem like a reasonable solution (and one that Apple will accept)?
Thanks for your time!
Why don't you want to use Apple's restoreCompletedTransactions? It just provides you with information about ALL the previous purchases, on any device, at any time.
http://developer.apple.com/library/mac/#documentation/StoreKit/Reference/SKPaymentQueue_Class/Reference/Reference.html#//apple_ref/occ/instm/SKPaymentQueue/restoreCompletedTransactions

Resources