I have a cloud function (environment: gen2) for verifying google play subscription purchases. I use two service accounts: Account 1 for building and deploying functions, and account 2 for interacting with the Google Play Developer API.
Account 1 permissions: Artifact Registry Create-on-Push Writer, Cloud Build Service Account, Editor, Logs Writer, Storage Object Admin.
Account 2 permissions: Cloud Functions Invoker, Cloud Run Invoker, Editor.
When I call the function from android studio, I get this error:
com.google.firebase.functions.FirebaseFunctionsException: UNAUTHENTICATED at com.google.firebase.functions.FirebaseFunctions$2.onResponse(FirebaseFunctions.java:388) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
When testing in Cloud Shell, I get this error:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"method": "androidpublisher.SubscriptionPurchasesService.Get",
"service": "androidpublisher.googleapis.com"
}
}
]
}
}
Python code:
import os
import json
from google.oauth2 import service_account
from googleapiclient.discovery import build
from google.cloud import secretmanager
from flask import Flask, request, jsonify
app = Flask(__name__)
def get_secret(secret_name):
client = secretmanager.SecretManagerServiceClient()
name = f"projects/{os.environ.get('GCP_PROJECT_ID')}/secrets/{secret_name}/versions/latest"
response = client.access_secret_version(name=name)
return response.payload.data.decode('UTF-8')
@app.route('/verify_purchase', methods=['POST'])
def verify_purchase():
try:
credentials_json = get_secret("functions_service_key")
except Exception as e:
return jsonify({"error": "Secret is not available"}), 500
credentials_dict = json.loads(credentials_json)
credentials = service_account.Credentials.from_service_account_info(credentials_dict)
androidpublisher = build('androidpublisher', 'v3', credentials=credentials)
data = request.get_json()
purchase_token = data.get('token')
package_name = "workout_wrecker"
subscription_id = "premium"
if not purchase_token:
return jsonify({"error": "Token is required"}), 400
try:
subscription = androidpublisher.purchases().subscriptions().get(
packageName=package_name,
subscriptionId=subscription_id,
token=purchase_token
).execute()
return jsonify(subscription), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
# This is the entry point for Google Cloud Function
def hello_http(request):
return verify_purchase()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
I’ve tried different permissions for both service accounts, but to no avail. I have also enabled google play android developer API. If more information is needed, comment and I will update. I’ve had no experience with cloud functions before, so please be patient with me, thank you!