googleapis / google-api-nodejs-client

Google's officially supported Node.js client library for accessing Google APIs. Support for authorization and authentication with OAuth 2.0, API Keys and JWT (Service Tokens) is included.
https://googleapis.dev/nodejs/googleapis/latest/
Apache License 2.0
11.45k stars 1.92k forks source link

Trying Google Apis (Server-to-server) but gives 401 error, even after assigning permissions to the service account. #3584

Open shubyaa opened 2 weeks ago

shubyaa commented 2 weeks ago

Hi, can anyone drop the set of permissions for the service account, I tried the sample test code to call the API

import { GoogleAuth } from "google-auth-library";
import fetch from "node-fetch";

// Path to your service account JSON key file
const serviceAccountPath = "./firebase_service_account_key.json";

// Initialize the GoogleAuth client with the service account key and required scope
const authClient = new GoogleAuth({
  keyFile: serviceAccountPath,
  scopes: ["https://www.googleapis.com/auth/androidpublisher"],
});

const getAccessToken = async () => {
  const client = await authClient.getClient();
  const { token } = await client.getAccessToken();
  if (!token) throw new Error("Failed to retrieve access token");
  return token;
};

const callPlayDeveloperAPI = async (packageName, subscriptionId, token) => {
  try {
    const accessToken = await getAccessToken();

    const url = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageName}/purchases/subscriptions/${subscriptionId}/tokens/${token}`;
    console.log("Request URL:", url);

    const response = await fetch(url, {
      method: "GET",
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.error("Error Response:", JSON.stringify(errorData));
      throw new Error(
        `Request failed with status ${response.status}: ${errorData.error.message}`
      );
    }

    const data = await response.json();
    console.log("Subscription Data:", JSON.stringify(data));
  } catch (error) {
    console.error("Failed to call Play Developer API:", error);
  }
};

// Replace with actual values
const packageName = "com.myexample.app";
const subscriptionId = "xyz_tag";
const token = "my_token";

// Call the function to make the API request
callPlayDeveloperAPI(packageName, subscriptionId, token).catch(console.error);

This code still returns me 401 error, I have also done inviting service account in my play console. I feel like for the scope android publisher, I might me missing some permissions. The permissions associated with the current service account are these :

image

If anyone know what I might be missing, it will be a great help.

Thanks.

shubyaa commented 2 weeks ago

I have also tried using client library, that too has the same issue

import { google } from "googleapis";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Path to your service account JSON key file
const serviceAccountPath = path.join(
  __dirname,
  "./firebase_service_account_key.json"
);

// Authenticate using a service account
const auth = new google.auth.GoogleAuth({
  keyFile: serviceAccountPath,
  scopes: ["https://www.googleapis.com/auth/androidpublisher"], // Required scope
});

// Initialize the Google Play Developer API
const androidpublisher = google.androidpublisher({
  version: "v3", // Version of the API
  auth: auth, // Pass in the authenticated client
});

// Function to check subscription status
const checkSubscriptionStatus = async (packageName, subscriptionId, token) => {
  try {
    const res = await androidpublisher.purchases.subscriptions.get({
      packageName: packageName,
      subscriptionId: subscriptionId,
      token: token,
    });
    console.log("Subscription Status:", res.data);
  } catch (error) {
    console.error("Error checking subscription:", error);
  }
};

// Replace with actual values
const packageName = "com.example.myapp";
const subscriptionId = "<xoxo>";
const token = "<token>"

// Call the function
checkSubscriptionStatus(packageName, subscriptionId, token);