I want to store in Android app data a token (a random number, e.g. 128 bit long) unique for each install. I also want to deliver this token to the backend after confirmed purchase. That is, the backend should reject hacker's attempts to store the token, if it is not after an app purchase.
In other words, I need to implement app "activation" so, that the activation is possible only after a genuine Google Play purchase.
An explanation why I need this:
Suppose I resell a $1 product for $2 in a $10 paid app.
The right to use this service by the user appears when he purchases my paid app.
If the user can fake app install, then he may obtain 1000 products for $10 and thus I would have $990 loss.
Thus I need to store on server side a token generated on confirmed (on the backend side) purchase.
Is this possible with Play Market?
In Flutter (and I believe, in plain Android, too) it can be done this way:
Every purchase needs to be "acknowledged".
After verifying the purchase receipt and the delivering the content to the user it is important to call InAppPurchase.completePurchase to tell the underlying store that the purchase has been completed. Calling InAppPurchase.completePurchase will inform the underlying store that the app verified and processed the purchase and the store can proceed to finalize the transaction and bill the end user's payment account.
Warning: Failure to call InAppPurchase.completePurchase and get a successful response within 3 days of the purchase will result a refund.
So, the task can be done this way:
The purchase is created (on the client app side, by contacting Play Store).
The app contacts my server with purchase token (and possibly other info).
During the request from the app the server retrieves the purchase by purchases.products.get to verify that the purchase is not forged by a hacker and increases users in-app funds.
App, after receiving a successful reply from the server, acknowledges the purchase by InAppPurchase.completePurchase.
If the app fails to acknowledge, the purchase is refunded in 3 days.
Related
I'm researching for developing an open source app that will get a sync feature in future.
This will be realized with Firebase Firestore. This feature should only be available to users subscribing to an abonnement via Google Play Billing.
Now, if I upload my google-services.json to my open source repo, anyone can compile the app and remove the check, whether there's an active subscription or not.
But if I don't upload my google-services.json, CircleCI can't build my project, since the file is missing.
Does anyone have experience in this matter, or some tips?
Thanks!
you should have a server for this. firebase or custom, doesn't matter, but the purchase, subscription, and renewal business rules should not be in your app providing the services based on the subscription status.
If all of the logic is in your app, without server, then you're bound to have issues with this. There's no way around that.
You should also assume that somebody will break your subscription logic (to provide free access) and the apk will be listed forever on something like apkmirror for anyone to get it.
Here's a suggested proper flow.
Server:
users need to have a login
have a list of products a user can subscribe to, with SKUs
that exist in the google play store, under your app's products
App:
app calls your server to get a list of products available for this user. you really care about getting the SKUs for this.
make request to google's billing client to get pricing for the list of SKUs
when customer purchases something using google's billing sdk, you'll get a purchase receipt object
send your purchase receipt to your server
Server:
the server will validate the purchase receipt with Google, where the server itself makes an API call to google to verify the authenticity of the receipt
if the receipt succeeds, the server returns a success code
App:
if the response from sending the receipt succeeds, then you make a new request to the billing SDK, this time to fulfill the purchase (close the transaction)
when fulfillment succeeds, call your server to notify that fulfillment is completed. send the lenght of the subscription (monthly, yearly...)
Server:
grant access to the subscription content the user just purchased
when the renewal time is up (which came from the fulfillment call), your server wakes up and calls google to renew the subscription
if renewal succeeds, user continues to have access to the subscription content
Yes, this is A LOT more work, but it is also dramatically more resilient and future proof than having a true/false flag in your app.
With that being said, if your subscriptions are $1 a year, and you expect to have no more than 10 users...then do the quick and easy way.
I've implemented a recurring subscription for Android In App Billing, but I'm wondering how the apps knows that the subscription is renewed. In testing, at least, the subscription is ended after 1 day. Will it be continued when the app is published on the store?
On iOS the testing subscription is renewed a couple of times. Enough to let you test when the subscription is renewed, but what is the best way to do this on Android?
Can I use the purchaseToken to let my server query Google Play API or do ever renewed subscription get a new purchaseToken?
In android IAP, The purchase token expires when the user manually cancels the subscription or disables the auto-renew. Otherwise, you will get a valid purchase token every time. In test mode, the tester's subscription automatically gets expired after 5 minutes but in production, it will work fine. So don't get worried about the production behavior. If you are running the app as a tester, you will get the below payment modes on the payment flow start.
You will have 2 options to test your implementation
Test Card(Always Approves)
Test Card(Always Declines)
By testing both of the cards, you can be sure about the implementation. Your app should be capable of handling both responses from IAP. If both flows goes well, You shouldn't be worried about it. You are ready to roll-out it on production. Here is the Official Docs, may help you to understand the entire flow.
If you designed custom flow to manage IAP, You can verify the IAP Token from backend using the Google Play Developer API and allow the user to consume the feature accordingly. For the custom flow, You can send custom JWT token from backend according to IAP Token expiry and set custom JWT Token exp claim. By using this method you can check the custom token is expired or not in the client-side, If it's happened so, You can fetch the new IAP token and send it to your backend. Your backend should validate that IAP token and issue new JWT token to user and cycle goes on. Let me know if you want the custom flow, I'll post it here.
You simply periodically query the Google Play server to check the items that the user own, if it is a subscription, it will reply that he/she owns it while it is active and therefore has not expired.
Do not forget to verify the signature of the received data, and much better using a server side verification
Android - protecting in app purchases with server side verification
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 have android app with subscription in-app purchase. Because I am using the subscription to deliver data from online service, I am using verification of purchase on server side via google play API (with purchase token the app send me after purchase). Majority of purchase tokens in my database are long alphanumeric strings, something like this :
djcbhbiertdkkotyuupnlmioppb.AO-J1Ozg0oasdfB3MAlWy-PihFE_nPVRMMfTW2_VPJt5KTKQA3CXNwyqweJAtUdIGTuOW9zEIIy-XS_4Un-a-Co6aEs__Adj1rZ4GtRxPKr04ph-l6nP2sU-w6e500YfTj5l0O8WEXF37yt
and these are verified OK. But from time to time I receive purchase tokens containing just 15 digits, like this :
781871156762279
And for these the result it always:
Google.GoogleApiException Google.Apis.Requests.RequestError
The purchase token was not found. [404]
Errors [
Message[The purchase token was not found.] Location[token - parameter] Reason[purchaseTokenNotFound] Domain[global]
]
I did not find anything about this in documentation. Am I missing something? Or could it be these are "fake" purchases from some cracked version of my app? Thanks.
I have received short purchase tokens in the same 15-digit format, and I believe that these are, in fact, attempts at fraudulent purchases.
It is not your app that is cracked. Rather, a user installs a special app onto a rooted device that performs a man-in-the-middle attack against your app, emulating the legitimate In-App Billing Service. When your app begins a purchase flow, this fraudulent app intercepts the purchase request, and returns a fake purchase token.
Apps that verify the token locally are vulnerable, because the same fraudulent app is used to verify the token.
Apps that send the token to the backend are probably safer, because the backend can make a request to the in-app billing API to verify the token independently. However, the app must wait for the backend verification to succeed before granting the user the purchased privileges.
Please see my other answer for more details on this attack.
I would like to setup subscription based billing for an app that will be sold through Google Play. Is it possible to sell the same subscription to the same user but on a different devices? So that every device that user tries to use the app on would need an active subscription?
I was thinking I could store the device id and user id on my own server and authenticate it that way, but is it correct that a user can't purchase the same subscription more than once? So would I need a pool of basically the same subscriptions if the user wishes to purchase multiple "licenses"? Can Google Play Billing handle any of this natively?
Thanks
The documentation from Google initially seems to make this impossible to achieve but digging deeper, I uncovered the following...
In the Google Play API version 2.0, you could create what was called an "unmanaged" product type that allowed the user to purchase the same thing multiple times. That seems to have partly disappeared in API 3.0 although the Gooogle Developer Console clearly supports this. I assume it's still supported because apps that used the 2.0 API are still out there and Google just can't drop support for that.
In 3.0 however, the "unmanaged" product type is not listed in the API docs but the docs state the following about making multiple purchases for the same product type (one-time purchase or subscription):
If you are using the Version 3 API, you can also consume managed items
within your application. You would typically implement consumption for
items that can be purchased multiple times (such as in-game currency,
fuel, or magic spells). Once purchased, a managed item cannot be
purchased again until you consume the item, by sending a consumption
request to Google Play. To learn more about in-app product consumption,
see Consuming Items
http://developer.android.com/google/play/billing/api.html#consume
IMPORTANT: Subscriptions CANNOT be consumed which means that if you want the customer to periodically renew their license, you will have to contact them and tell them that they must purchase the license again. That's a downside if your service requires a periodic renewal.
To obtain what you are after, you will need a backend server to handle the registration of devices and store tokens the apps receive from Google Play when purchasing. When a user wants to purchase your license, feature, service (or whatever) from another device, the other device MUST first release its "ownership" of the product with Google Play, through a process known as "consuming". It would work something more or less like this:
The first device makes a purchase and receives a purchaseToken
string from Google Play.
The purchaseToken along with the device ID is sent from the app to your server and stored.
The user goes to the second device and wants to purchase the license as well for that device. The app first needs to go to your server and obtain the purchaseToken (that the first device uploaded) and then call Google Play with consumePurchase which releases the "ownership" of the product from the user.
The app then purchases the new license (or whatever) from Google Play, gets a new purchaseToken and stores it on your server along with its device ID.
In essence, Google Play won't keep track of which device has the product. It only associates the Google Account with the product being purchased. It's up to your app and server to manage the licenses.
There is one potential problem I see that you need to address. If for some reason the app fails to send the purchaseToken back to your server (your server is down, the user dropped their device and broke it, your app crashes before it saves the token on the device, etc.), then you may not know if the user paid for the service. Google does provide a server API that lets your backend server query Google Play on Google's server for information about purchases, but I'm not familiar with it nor its limitations.
You will need to implement in app purchases as you would for any other in app item.
Make sure when you create your item in the Dev Console, it is unmanaged, as managed items can only be purchased once per account.
When you receive a confirmation on purchase of your unmanaged item, send the details like the unique ID to your server and store them there.
Now whenever your app starts, check with your server if it is an authorized device. If it isn't, prompt the user to buy it. If it is, let them continue to the app.
This only works if you need a one time payment. If you need a subscription, you will have to make it up of multiple one time payments, as subscriptions are like managed purchases and can only be paid for once by any account.