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.26k stars 1.91k forks source link

Getting permission denied while getting subscription details from pub/sub events using service account credentials #3445

Open bhavya3024 opened 4 months ago

bhavya3024 commented 4 months ago

Hi there, I used google cloud pub/sub api to receive messages using the endpoint url, here I was able to receive events in the backend, but when I tried getting subscription details using the service account credentails, I got permission denied. It worked successfully when tried using OAuth redirecting to the browser, but I need to handle it in the backend to store/modify subscription details in the database, so OAuth2 doesn't seem to be viable option.

I have tried the following code snippet.

require('dotenv').config();
(async () => {
    const subscription = {
        message: {
            data: '<sample-subscription>',
            messageId: '10553462436995277',
            message_id: '10553462436995277',
            publishTime: '2024-02-27T12:30:55.34Z',
            publish_time: '2024-02-27T12:30:55.34Z'
        },
        subscription: '<subscription-id>',
    };

    const decodedData = Buffer.from(subscription.message.data, 'base64').toString('utf-8');
    console.log(decodedData);
    const {
        subscriptionNotification: { purchaseToken, subscriptionId },
        packageName,
    } = JSON.parse(decodedData);

    console.log(JSON.parse(decodedData));

    const { google } = require('googleapis');

    const androidpublisher = google.androidpublisher({
        version: 'v3',
        auth: new google.auth.JWT({
            keyFile: './creds.json', // service account creds, i saw in the google console that it has owner permissions
            scopes: ['https://www.googleapis.com/auth/androidpublisher'],
        }),
    });
    const response = await androidpublisher.purchases.subscriptions.get({
        packageName: packageName,
        subscriptionId: subscriptionId,
        token: purchaseToken,
    });
    console.log(response);
})();

The error I am getting is:

{  
status: 401,
  code: 401,
  errors: [
    {
      message: 'The current user has insufficient permissions to perform the requested operation.',
      domain: 'androidpublisher',
      reason: 'permissionDenied'
    }
  ],
}

these are permissions I saw in the google cloud console. image

Don't know what to do in this case! Thanks in advance! @proppy @dazuma @jskeet @hansoksendahl @andrelaszlo

andrelaszlo commented 4 months ago

Hi @bhavya3024! Not sure why I'm tagged in this issue, but I'd never complain about being mentioned in the same sentence as Jon Skeet 😉

I'm not using the nodejs client library, but here are some ideas:

By the way, Owner is generally too broad for service accounts - to consume Pub/Sub messages, the SA needs the Pub/Sub Subscriber (roles/pubsub.subscriber)) role on the subscription at least.

bhavya3024 commented 4 months ago

Hi @andrelaszlo I use AWS Lambda in backend, if I try to use ADC config file and use them inside lambda, will it work ?

andrelaszlo commented 4 months ago

Hi @andrelaszlo I use AWS Lambda in backend, if I try to use ADC config file and use them inside lambda, will it work ?

Something like that, yeah. I think you can fetch secrets from AWS Secret Manager and store them in GOOGLE_APPLICATION_CREDENTIALS for example. Use a service account key though.