The application is an Android client for a remote service on which all users have accounts and can make purchases of non-consumable items. Each purchase is tied to the account they were purchased on. The current purchase scheme is as follows:
- The client initiates the purchase with the Google Play in-app billing service. The purchase request contains the payload which uniquely identifies the account.
- When the purchase is successfully completed, the client gets back the purchase data which contains the payload and the purchase token. Also it has a signature for the received data which is currently not checked though.
- The client sends the purchase token to the server. At this point it has to be authenticated.
- The server receives the purchase token. The server authenticates with the Google Play service using its service account key and receives the purchase data for the given token. The data contains the original payload and the information regarding the purchase.
- The server validates the purchase data: it is verified that the payload matches the currently logged in user id, the purchase is not yet consumed, and has successfully been paid for.
- If the verification is successful, it is marked that the client has purchased the product on the server and the client receives a confirmation, otherwise the client receives a rejection.
What could go wrong with this scheme? For instance, it worries me that the signature is not used anywhere. However, I don't see what use is in it if the server receives the data directly from Google Play. At worst, it can receive a wrong token, but the payload contains the user id, so the purchase will be rejected if it has been made for another account. Sending the same token twice is also useless since the product is non-consumable: it either has been purchased or hasn't. But maybe I'm missing something here or there is some other flaw I don't see?