Google Cloud Platform
Created: 2019-05-14 11:52:50 -0700 Modified: 2019-05-14 12:21:39 -0700
Service accounts, permissions, and Android
Section titled Service accounts, permissions, and AndroidIn May, 2019, I wanted to be able to validate purchases from my own server that an Android user would report to me after actually transferring money to Google. So the flow would be something like this:
- User makes a purchase in the Android app
- User sends money to Google
- Google sends a purchase token to the user that indicates that they’ve made the purchase
- User sends token to my server
- My server asks Google if the user really made the purchase
For step #5, Google advertises the get Purchases.products API. On their documentation for that API, they mention that it requires authentication and authorization. Finding those details was impossibly difficult. Here’s what I learned:
A service account is just like it is on most platforms: it’s an account granted to a program as opposed to a person. However, regular user accounts can act as this service account. All accounts, regardless of types, have roles that grant permissions to various resources. So what I assumed originally is that I would give the service account permission to access the purchases API. There was no such permission, and that’s when I found out that Android only intersects with Google Cloud Platform rather than being “fully committed” to it like, say, Google Translate. In order to use the Google Translate APIs, you need to manifest the right permissions, some of which look like this:
cloudtranslate.generalModels.batchPredict
cloudtranslate.generalModels.get
cloudtranslate.generalModels.getIamPolicy
cloudtranslate.generalModels.predict
cloudtranslate.generalModels.setIamPolicy
cloudtranslate.glossaries.batchPredict
cloudtranslate.glossaries.create
cloudtranslate.glossaries.delete
cloudtranslate.glossaries.get
cloudtranslate.glossaries.getIamPolicy
cloudtranslate.glossaries.list
cloudtranslate.glossaries.predict
cloudtranslate.glossaries.setIamPolicy
cloudtranslate.languageDetectionModels.getIamPolicy
cloudtranslate.languageDetectionModels.predict
cloudtranslate.languageDetectionModels.setIamPolicy
cloudtranslate.locations.get
cloudtranslate.locations.getIamPolicy
cloudtranslate.locations.list
cloudtranslate.locations.setIamPolicy
cloudtranslate.operations.cancel
cloudtranslate.operations.delete
cloudtranslate.operations.get
cloudtranslate.operations.getIamPolicy
cloudtranslate.operations.list
cloudtranslate.operations.setIamPolicy
cloudtranslate.operations.wait
For Android, the Google Play Console manages permissions from any users, not the Google APIs Console, so the steps are generally this (reference, although the steps have changed slightly):
- Go to the Google Play Console
- Go to Developer account → API access
- Create a new project
- Create a new service account (this takes place on the Google APIs Console)
- Grant a role (THIS IS NECESSARY) that is something like “Service Account User”. Without this, your service account won’t show up in the Play Console. Service Account User only has 5 permissions, the important one being impersonation as the service account. This is likely better than choosing a role like Project Viewer since that has 852 permissions.
- If you accidentally chose the wrong role, you can manage that in the IAM tab and then click the ✏ under “Inheritance”.
- Grant a role (THIS IS NECESSARY) that is something like “Service Account User”. Without this, your service account won’t show up in the Play Console. Service Account User only has 5 permissions, the important one being impersonation as the service account. This is likely better than choosing a role like Project Viewer since that has 852 permissions.
- Back in the Play Console, grant Android-specific permissions like “Financial Data → Manage orders” (I think that’s the one that lets you validate receipts).
- At some point, download the private key JSON file from the Google APIs Console so that you can act as this service account from your code.
When you finally end up calling the Purchases API, my understanding is that this happens:
- You specify your private key that you downloaded from the Google APIs Console
- Google checks your service account’s identity. It ensures that the account exists and that your credentials are correct.
- Google sees that the API is for Android, for which it doesn’t explicitly maintain permissions via the service account.
- Google somehow funnels the request through the Google Play side of things
- Google Play checks the Android-specific permissions that you set to authorize your app
- The API runs and returns the response that you expect
Apparently, even after you’ve set everything up correctly, you may still have to wait for permission propagation (reference).