Is the following approach necessary and/or best practice?
In my client call a back end server end point getRandomString with a sign in token to uniquely identify the user.
The server generates a random string and adds it to the user's list of available random strings
The client uses this random string as the developer payload.
When I come to verify the purchase token on the server I check that the developer payload is one in the users "random string" array.
If it's in the list, remove it, and validate the purchase, otherwise decline validation.
I can't find much in the way of guidance on this either in Google Docs, or on SE or posts seem to be from 5 years ago.
Is the above approach the right way to go. And also, is using developer payload actually necessary?
I think I've identified the source of the confusion on Developer Payload now. Years back when I was coding with InAppPurchasing developer payloads was an additional parameter in the launchPurchaseFlow function, but the new Billing Library with its launchBillingFlow does not support the developer payload any more. It is apparently now classed as a legacy field. See here for example. And in this Google post, we have confirmation:
Hi
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).
Thanks
Related
I have a question regarding implementing Google speech, or google cloud API in general, for Android
What I want is to have multiple certificates or API keys for different clients.
In practice, I can have 10 different Android devices, linked to Server 1 for Client 1, and 20 different Android devices, linked to another server for Client 2.
I would like to split the billing of this clients but using same Android project/package.
In https://github.com/GoogleCloudPlatform/android-docs-samples/tree/master/speech/Speech example there is an OAuth2 Credential used, but the problem here is that you can have only 1 OAuth2 Credential for 1 project, but in this case I would need multiple, so this is not an option.
Even if I implement OAuth2 on a server and refresh Tokens for devices, I would need to have multiples.
In the end I would have 1 google account, with multiple client configuration, where each client is seperate when checking billing info and also for restricting purposes. If I have multiple keys I can just disable one and that is
So my question is (if I can split billing for specific API key/service account, or just know the usage used)
How to change example implementation to use API keys or different Service accounts with GoogleCredentials.fromstream()? Do I need to manually implement API requests to google REST API, or is this possible in Android with something like:
SpeechClient.create(SpeechSettings.newBuilder().setCredentialsProvider {API_KEY}.build())
You can't have billing details per API Keys used on Speech API. Here, the easiest solution is to have one project per customer. When a request come in, check the user Id (because the user is already authenticated and you have a OAuth2 token) on the server and, according with the user info stored somewhere (we use Firestore for user profile storage), call the Speech API in the correct project.
You have 1 billing per project, and a free tier per project also!
Edit 1
It's possible I wasn't clear. Here a schema.
The newly available Google Play Billing library does not support the SubscriptionManager of Unity IAP.
Usually, I would validate the receipt with the SubscriptionManager and check the is_subscribed, is_expired, etc attributes and act accordingly.
The documentation of Unity is not up to date with this new information. The Google Play Billing documentation offer no solution or insight as to how to validate that a subscription is still valid. "Not supported" is hardly a valid response, subscriptions are part of a lot of games and software made with Unity.
How can I validate that a Google Play subscription is valid and not expired in a Unity Project using the Unity IAP. Failing to be able to use Unity IAP, any other solution or insight is welcome.
It appears that this new plugin makes it mandatory to validate user subscriptions server-side. When implementing the plugin, I had to create a back-end service that provided the expiry date back to our app since we couldn't use SubscriptionManager to grab that information anymore.
I can't really recommend a specific way of doing this, because everyone's back-end will be different. For us, we utilize Docker containers on DigitalOcean droplets that our app and database can communicate with. This allows us to have a centralized location for back-end services, which we write in Python using Flask.
We have set up one that can go through our database, find every subscription that has expired based on the saved DateTime, and validate whether it has renewed or not. We added an extra endpoint to that service for grabbing the expiry date of a Google Play subscription, as mentioned above.
Subscription information can be obtained by accessing the Google Play REST API's purchases.subscriptions.get. This will return a SubscriptionPurchase object, which provides relevant information that you can then process to find out attributes such as is_subscribed, is_expired, etc.
It may be possible to send this directly from your Unity app/game, however this may also make man-in-the-middle attacks possible (admittedly my knowledge in this area isn't quite there, so I recommend you do your own reading on this).
Also as just a general suggestion, I recommend you try to post questions across both here and the UnityIAP sub-forum. The UnityIAP support folks are super active and even if they can't help because this is a Google implementation, it should definitely put it on their radar! I try to post there whenever I can as it allows them to make improvements to UnityIAP. (:
Yes at the moment we should use server-side API for getting Subscription related info. As SubscriptionManger was dependent on developer payload which is deprecated. See 2nd para https://developer.android.com/google/play/billing/developer-payload
I'm developing a pay for win Android app, in which users are, among others, ranked according to the amount they have spent. The payments are Android in-app purchases.
My questions are:
Is an authentication system required for my users, in order to purchase and be ranked? In other words: instead of using an authentication system, could I use the UUID of the phone, or its MAC address, or any other piece of information that would actually act as an authentication system? If yes: why isn't there any other Android app that proceed in this way (indeed, they use Facebook/Google authentication, or e-mail + password authentication, etc.)?
Is there any Java ranking library that I could use and bind it to the Android in-app purchases? In particular: does Google offer such an API?
Is it a good idea to use Google's authentication and ranking based on Google Play? The ranking criteria must also be the total spent amounts.
Authentication and authorization
Firstly, I would like to make the distinction between authentication and authorization.
Authentication is a way to determine a user apart from other users. Authentication allows a developer to identify Jane Doe as a separate entity from all other users. Authentication is often a precursor to authorization.
Authorization pertains to what actions a user can take on particular resources. Authorization deals with the what, when, how as opposed to the authentication that deals with who.
To state your questions using more definitive language you are asking for best practices relating to:
Authenticating a user inside an application that is available on the Google Play Store, and
Calculating totals related to Android's In-App purchasing, and
Authorizating a user to take a claim action on a prize entity depending on the aforementioned total aggregate
Recommendations
I would highly suggest you use Google's OAuth 2.0 service to authenticate users as opposed to building your own authentication framework or implementing any other authentication framework, especially if this application is only used within th Android ecosystem. I recommend this because:
Android users already have a Google account, and
Implementing your own authentication framework requires very niche skills which usually require a team of people, and
Google already offers an Subscription and In-App Purchasing API which can be queried to rank you users, and
You will already have implemented this API to support in app purchasing to begin with
I would highly suggest you do not use MAC address or UUID authentication because
On a rooted phone I can change my MAC address, and
It does not uniquely identify a user across multiple devices, and
Using this type of authentication would not provide any benefit to your second goal of authorizing actions based on a total aggregate
In other words by using Google's authentication mechanism you can not only uniquely identify users across multiple devices, but you can also leverage the in app payment system to build your particular authorization logic.
The In-App Purchasing API already contains the necessary information you want since you will need to implement it to support in app purchasing to begin with. You might as well use it as a basis for ranking since it is readily available, secure, and contains the information you need with well documented ways of accessing it.
Additionally, you may want to look at the promotional capabilities and one time product-specific billing features functions and related APIs. This might fit your use case and it may make your application more secure and standardized.
Using the provided authentication framework and in app purchasing capabilities standardizes your application up until you implement the claim your prize functionality. People enjoy standardization because they become familiarized with it, and it provided a level of trust, so I would definitely investigate the other aforementioned APIs to see if your prize idea can be based off a foundation provided by Android. This would standardize your app all the way through and, in my opinion, would be best practice.
Summary
I would provide some sample code but your questions are still a but high level to provide anything useful in the way of code snippets. To summarize though my recommendations are as follows
Leverage the Google OAuth 2.0 framework for authentication, and
Leverage the In-App purchasing API and related APIs as a way to calculate total and rank users, and
Investigate the promotional capabilities, or one time product-specific features already provided by Google to see if it fits your use case, and
Avoid using MAC addresses and UUIDs for authentication for the reasons I outlined above
Edit ....
After rereading your title I realized I glossed over the fact that, as I understand it, the term ranking and it's related functionality as used by Android is mostly centered around where you application sits, popularity wise, in comparison to other applications. I have not seen the term used by Android to refer to internal ranking of users against some developer-defined criteria ( total, in your case ).
I'm not saying it does not exist, just that every time I see ranking it refers to application popularity. Therefore I would refrain from using that as a query term when researching how to build this application as you will likely get a plethora of false positives.
What I think you want, to reiterate, is
Authentication
Calculating in app purchasing totals
Promotional or one time features based on that total
Those terms will suite you much better. Please feel free to start a new post when you get further in to the project if you need assistance consuming the APIs
In Android Documentation there is this recommendation:
Security Recommendation: It’s good practice to pass in a string 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.
What are the best practices to generate this string?
When the app is on its own, the best approach is to
use the obfuscated Google Play LVL user id and, after a separator
add a secure random information (aka nonce) and, depending on your needs,
you can add additional info identifying e.g. the point in time
This way, you can
associate LVL and IAB information and
the IAB service responses are a bit more secure than they would be without the nonce
The following vulnerabilities remain:
Having your app check LVL/IAB is insecure in general because the checks can in principle be overridden after reverse engineering.
With the IAB nonce being set upon creation of the buy intent (rather than upon the validity request itself), there's no way to validate that the response you get does not come from a re-play attack.
The IAB V3 information is cached inside the IAB service on the Android device, so it's not even guaranteed that you'll get the latest information; the service will silently pass cached information to the app if the device is offline or the service decides that the validity of the cached information needs not be re-validated right now.
The only way to further improve security is to use a server-based approach for LVL/IAB validation.
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