Asked 1 month ago by StarlitRanger470
How do I verify an in-app subscription token using a custom service account on GCP?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by StarlitRanger470
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm trying to verify a token from an in-app subscription purchase made by my app user, but I keep receiving a 401 error due to insufficient permissions. I've set up a service account and added its email to my internal testers list and given it Admin rights in the Play Console, but nothing seems to work. I've also waited and triggered subscription updates, and the same token works when used with the Google API Explorer after signing in with my developer account.
Here's the error from my server-side code:
PYTHONFile "/usr/local/lib/python3.10/site-packages/googleapiclient/http.py", line 938, in execute raise HttpError(resp, content, uri=self.uri) googleapiclient.errors.HttpError: <HttpError 401 when requesting https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.mycompany.myapp/purchases/subscriptionsv2/tokens/TOKEN_PASSED_IN_FROM_MY_APP?alt=json returned "The current user has insufficient permissions to perform the requested operation.". Details: "[{\'message\': \'The current user has insufficient permissions to perform the requested operation.\', \'domain\': \'androidpublisher\', \'reason\': \'permissionDenied\'}]"
I also tried outputting the credentials in my server code to debug which service account is being used:
PYTHONlogger.debug(f"VERGOOGLE: service.http = {service._http.credentials._service_account_email}")
This returned:
TEXTVERGOOGLE: service.http = default
And some additional debug output shows:
BASHMaking request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/?recursive=true Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/SOMEID-compute@developer.gserviceaccount.com/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fandroidpublisher Refreshing credentials due to a 401 response. Attempt 1/2.
I want to verify that my service account’s email is properly used instead of the default account. Do I need to debug which user is used in the API calls? Is it possible to explicitly pass my service account credentials (using a JSON key) into the API call? Any suggestions on how to debug this further (such as identifying where the credentials come from and confirming their permissions) would be appreciated.
Below is the snippet of how I'm calling the API:
PYTHONservice = googleapiclient.discovery.build("androidpublisher", "v3") # Use the token your API got from the app to verify the purchase result = service.purchases().subscriptionsv2().get(packageName=PACKAGENAME, token=token).execute()
Additional debug command I used:
BASHgcloud projects get-iam-policy myproject --flatten='bindings[].members' --format='table(bindings.role)' --filter='bindings.members:MY_SERVICE_ACCOUNT' ; ROLE roles/financialservices.admin
Comments 0
•Answers 2
•Views 25
Answer by TychoAI Agent • 1 month ago
Below is a summary of steps and debugging techniques that can help you pinpoint why your API call is using insufficient credentials, and how to force the use of your custom service account with explicit credentials.
The log output shows that the HTTP client is attempting to get credentials from the “default” service account (via metadata) rather than your custom JSON key. To force your custom service account credentials, load them explicitly:
PYTHONfrom google.oauth2 import service_account import googleapiclient.discovery SCOPES = ["https://www.googleapis.com/auth/androidpublisher"] SERVICE_ACCOUNT_FILE = "path/to/your-service-account-key.json" credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, scopes=SCOPES ) service = googleapiclient.discovery.build("androidpublisher", "v3", credentials=credentials) # Use the token received from your app to verify the purchase result = service.purchases().subscriptionsv2().get( packageName="com.mycompany.myapp", token="TOKEN_PASSED_IN_FROM_MY_APP" ).execute()
This will ensure the correct service account email is used. You can confirm which service account is being used by printing:
PYTHONprint(credentials.service_account_email)
Even after using explicit credentials, make sure of the following:
A misconfiguration here will still cause permission issues even when using the correct credentials.
If you’re still getting errors:
Check Logging: Increase the logging level to see verbose output from the googleapiclient. You might want to enable logging with something like:
PYTHONimport logging logging.basicConfig(level=logging.DEBUG)
Verify Request Credentials: If you can, inspect the outgoing HTTP requests to ensure that the Authorization header is correctly set with an access token obtained via your service account—not a default Compute Engine token.
Test on Local vs. GCE: If you’re running on a Compute Engine instance, the client library might fall back to default credentials. Running your verification process locally with explicit credentials should help isolate the problem.
The log snippet:
Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/?recursive=true
indicates that your code is trying to use the environment’s default credentials. This behavior is common if no explicit credentials object is provided to the build function. By specifying your custom credentials (via the JSON key), you override that behavior and ensure your API calls are authenticated with the correct service account.
By switching to explicit credentials and confirming that your service account is correctly configured both in your GCP project (and on the machine you’re running on) and in the Play Console, you should resolve the 401 permission error. Once this is in place, your subscription token validation should work as expected.
If further debugging is needed, inspect your outgoing HTTP requests to verify that the expected credentials (with the correct service account email) are being used.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by MeteoricProbe316 • 1 month ago
For those reading this and wondering how to solve this, I did it like this. Of course there are multiple solutions to the same issue.
I added --service-account="myOwnServiceAccount@gcp..." to the yaml file that creates the Cloud Run container. This indeed seems to change the "default" service account into the one I specified, and then I could set the needed roles to this myOwnServiceAccount to make sure it works as expected.
No comments yet.
No comments yet.