Skip to content

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 Android

In 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:

  1. User makes a purchase in the Android app
  2. User sends money to Google
  3. Google sends a purchase token to the user that indicates that they’ve made the purchase
  4. User sends token to my server
  5. 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”.
  • 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).