Saad
Saad

Reputation: 53879

Unable to use Google Play Developer API even after server to server authentication

I am trying to call Purchases.Subscriptions: get from my local server, but I am getting an error message saying Error: Login Required.

I have already created a service account with a role of Project Owner as described here. I then set the GOOGLE_APPLICATION_CREDENTIALS environment variable and made it point to the JSON file that was downloaded as mentioned here.

Lastly, I tried running some example code that was meant for server-to-server authentication based off the website docs example to see if I could authenticate successfully:

import { google } from 'googleapis'

async function main() {
  try {
    const auth = new google.auth.GoogleAuth({
      scopes: ['https://www.googleapis.com/auth/androidpublisher']
    })

    const authClient = await auth.getClient()
    const project = await auth.getProjectId()
    const publisher = google.androidpublisher('v3')

    const result = await publisher.purchases.subscriptions.get({
      packageName: 'com.mywebsite.subdomain',
      subscriptionId: 'com.mywebsite.subscription_name',
      token: '...my purchase token...'
    })

    console.log(result)
  } catch (error) {
    console.error(error)
  }
}

main()

I just used the Billing API instead of the Compute API, otherwise my example is the same as the one given in the docs. I am not sure why I am having issues, any help would be appreciated!


Full error:

{ Error: Login Required
    at Gaxios.request (/Users/squadri/Desktop/googlenode/node_modules/gaxios/src/gaxios.ts:86:15)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  response:
   { config:
      { url:
         'https://www.googleapis.com/androidpublisher/v3/applications/com.mywebsite.subdomain/purchases/subscriptions/com.mywebsite.subscription_name/tokens/...my%20purchase%20token...',
        method: 'GET',
        paramsSerializer: [Function],
        headers: [Object],
        params: [Object: null prototype] {},
        validateStatus: [Function],
        retry: true,
        responseType: 'json',
        retryConfig: [Object] },
     data: { error: [Object] },
     headers:
      { 'alt-svc': 'quic=":443"; ma=2592000; v="46,43,39"',
        'cache-control': 'private, max-age=0',
        connection: 'close',
        'content-encoding': 'gzip',
        'content-type': 'application/json; charset=UTF-8',
        date: 'Tue, 20 Aug 2019 04:41:29 GMT',
        expires: 'Tue, 20 Aug 2019 04:41:29 GMT',
        server: 'GSE',
        'transfer-encoding': 'chunked',
        vary: 'Origin, X-Origin',
        'www-authenticate': 'Bearer realm="https://accounts.google.com/"',
        'x-content-type-options': 'nosniff',
        'x-frame-options': 'SAMEORIGIN',
        'x-xss-protection': '1; mode=block' },
     status: 401,
     statusText: 'Unauthorized' },
  config:
   { url:
      'https://www.googleapis.com/androidpublisher/v3/applications/com.mywebsite.subdomain/purchases/subscriptions/com.mywebsite.subscription_name/tokens/...my%20purchase%20token...',
     method: 'GET',
     paramsSerializer: [Function],
     headers:
      { 'x-goog-api-client': 'gdcl/3.1.0 gl-node/10.16.1 auth/5.2.0',
        'Accept-Encoding': 'gzip',
        'User-Agent': 'google-api-nodejs-client/3.1.0 (gzip)',
        Accept: 'application/json' },
     params: [Object: null prototype] {},
     validateStatus: [Function],
     retry: true,
     responseType: 'json',
     retryConfig:
      { currentRetryAttempt: 0,
        retry: 3,
        retryDelay: 100,
        httpMethodsToRetry: [Array],
        noResponseRetries: 2,
        statusCodesToRetry: [Array] } },
  code: 401,
  errors:
   [ { domain: 'global',
       reason: 'required',
       message: 'Login Required',
       locationType: 'header',
       location: 'Authorization' } ] }

Upvotes: 2

Views: 2945

Answers (3)

Ahmed Sabry
Ahmed Sabry

Reputation: 494

You need to pass the auth field (authClient) to google.androidpublisher

const publisher = google.androidpublisher({
  version: 'v3',
  auth: authClient
})

Upvotes: 0

user6277878
user6277878

Reputation: 61

Try this code snippet for example.
Print apks list of specific packageName using googleapi, androidpublisher and service account authentication (v3).

const {google} = require('googleapis');
const key = require('./privateKey.json')
const packageName = "com.company.example"

let client = new google.auth.JWT(
  key.client_email,
  undefined,
  key.private_key,
  ['https://www.googleapis.com/auth/androidpublisher']
)
const androidApi = google.androidpublisher({
  version: 'v3',
  auth: client
})

async function getApksList() {
    let authorize = await client.authorize();
    //insert edit
    console.log('authorize :', authorize);
    let res = await androidApi.edits.insert({
        packageName: packageName
    })
    //get edit id
    let editId = res.data.id
    const res = await androidApi.edits.apks.list({
        editId: editId,
        packageName: packageName
    });
    console.log(`Result ${(JSON.stringify(res))}`);
}
getApksList().catch(console.error);

Upvotes: 6

pgeimer
pgeimer

Reputation: 103

You need to add your JSON key file to google.auth.GoogleAuth:

const auth = new google.auth.GoogleAuth({
  keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
  scopes: ['https://www.googleapis.com/auth/androidpublisher']
});

See: https://github.com/googleapis/google-api-nodejs-client/blob/master/samples/jwt.js

Upvotes: 0

Related Questions