Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request had insufficient authentication scopes #2311

Closed
wbelk opened this issue Jul 30, 2020 · 8 comments
Closed

Request had insufficient authentication scopes #2311

wbelk opened this issue Jul 30, 2020 · 8 comments
Assignees
Labels
needs more info This issue needs more information from the customer to proceed. type: question Request for information or clarification. Not an issue.

Comments

@wbelk
Copy link

wbelk commented Jul 30, 2020

I'm trying to access google.webmasters('v3') on behalf of a consenting user. I redirect them to the consent url, then store refresh_token and access_token from the callback. I'm getting the following error: Request had insufficient authentication scopes

I'm sure I'm doing something dumb or omitting an important process step. Can someone point me in the right direction?

My code looks like:

const {google} = require('googleapis')
const webmasters = google.webmasters('v3')

const oauth2Client = new google.auth.OAuth2(
  '****',
  '****',
  m.serverAddress + '/google-apis/callback'
)

oauth2Client.credentials = {
    refresh_token: '****',
    access_token: '****'
}
google.options({auth: oauth2Client})

const res = await webmasters.searchanalytics.query({
    siteUrl: 'https://' + domain,
    requestBody: {
      startDate: `${year}-${month}-${day}`,
      endDate: `${year}-${month}-${day}`
    },
    dimensionFilterGroups: [
      {
        groupType: 'and',
        filters: [
          {
            dimension: 'query',
            operator: 'equals',
            expression: unescapedKp
          }
        ]
      }
    ]
  })
@JustinBeckwith
Copy link
Contributor

Greetings! You need to pass a list of required scopes for the user to accept in your generateAuthUrl call:
https://github.com/googleapis/google-api-nodejs-client#generating-an-authentication-url

Please take a look there, and let us know if you have any questions!

@JustinBeckwith JustinBeckwith added needs more info This issue needs more information from the customer to proceed. type: question Request for information or clarification. Not an issue. labels Jul 30, 2020
@wbelk
Copy link
Author

wbelk commented Jul 30, 2020

@JustinBeckwith thank you. I've already passed the scope at the time of the user's consent, I need to generate the consent URL again?

So I would need to await oauth2Client.getToken(code) with the code I've already stored from the original consent callback, and exchange that code again for a brand new access_token before every instantiation of oauth2Client each time I want to access the api on behalf of that user?

@JustinBeckwith
Copy link
Contributor

More or less, yeah. The first time the user goes through the consent flow, you're going to get both a refresh_token and a access_token back:
https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens

If you want to use the tokens later, you need to securely store the refresh token, and use it when you re-construct your OAuth2Client object. The setCredentials method lets you pass in that refresh token, and the library manages fetching a new access token under the hood for you!

@wbelk
Copy link
Author

wbelk commented Jul 30, 2020

I've tried three configurations, all generate errors for me. I'm still totally lost as to why I would need to generate an auth url for a user that has already consented and for whom I have already saved the refresh_token. I need to access the api in an entirely new future session/instantiation using existing refresh_token.

Sorry this is making me feel really dumb and frustrated. What am I missing?

(1) Error: invalid_grant:

const {google} = require('googleapis')
const webmasters = google.webmasters('v3')

const oauth2Client = new google.auth.OAuth2(
  '***',
  '****',
  m.serverAddress + '/google-apis/callback'
)
const scopes = [
  'https://www.googleapis.com/auth/webmasters.readonly'
]

const url = oauth2Client.generateAuthUrl({
  access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
  scope: scopes
  // prompt: 'consent' use this if need new refresh_token
})

// url does not contain `code`, and user is already consented, so there will be no callback to obtain a new code

const {tokens} = await oauth2Client.getToken( 'SAVED CODE FROM INITIAL CONSENT')

// BREAKS ON LINE ABOVE -- Error: invalid_grant /node_modules/googleapis-common/node_modules/gaxios/build/src/gaxios.js:85:23

oauth2Client.setCredentials(tokens)

(2) Error: Login Required:

const {google} = require('googleapis')
const webmasters = google.webmasters('v3')

const oauth2Client = new google.auth.OAuth2(
  '***',
  '****',
  m.serverAddress + '/google-apis/callback'
)
const scopes = [
  'https://www.googleapis.com/auth/webmasters.readonly'
]

oauth2Client.generateAuthUrl({
  access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
  scope: scopes
  // prompt: 'consent' use this if need new refresh_token
})

oauth2Client.setCredentials({
    refresh_token: 'SAVED REFRESH TOKEN FROM INITIAL CONSENT'
  })

(3) Error: Login Required

const {google} = require('googleapis')
const webmasters = google.webmasters('v3')

const oauth2Client = new google.auth.OAuth2(
  '***',
  '****',
  m.serverAddress + '/google-apis/callback'
)

oauth2Client.setCredentials({
    refresh_token: 'SAVED REFRESH TOKEN FROM INITIAL CONSENT'
  })

@JustinBeckwith
Copy link
Contributor

Oh no! There's a misunderstanding here - in your original code, you didn't show how you set the scopes. The refresh_token does encapsulate the scopes you originally requested. In example #1, I think the problem is you want to do something like:

const {google} = require('googleapis')
const webmasters = google.webmasters('v3')

const oauth2Client = new google.auth.OAuth2({
  clientId: '*****',
  clientSecret: '******',
  redirectUri: '****',
});
oauth2Client.setCredentials({
  refresh_token: 'SAVED REFRESH TOKEN FROM INITIAL CONSENT'
});

That should be enough! The next call you make through that client should "just work".

@wbelk
Copy link
Author

wbelk commented Jul 31, 2020

Also another data point, I know that the refresh_token above works for my test user, I'm using that same token successfully with the Google Ads API package https://www.npmjs.com/package/google-ads-api which requires all the same client credentials and refresh_token

Screen Shot 2020-08-01 at 9 45 50 AM

@wbelk
Copy link
Author

wbelk commented Aug 4, 2020

@JustinBeckwith I was able to get an hour of help from @soldair and what an adventure. We were able to log and verify that we are getting back a refreshed access_token from setCredentials().

We were also able to perform http requests to https://www.googleapis.com/oauth2/v3/token with the refresh_token to generate a fresh access_token and then get a full successful response with body.rows data from https://www.googleapis.com/webmasters/v3/sites/siteUrl/searchAnalytics/query.

As it relates to this library, it seems like something is happening with webmasters.searchanalytics.query() on the Google server side and it returns Error: Login Required.

Now that I can query the webmasters endpoint via http successfully, maybe I can help scout out this Login Required error. Any idea what the range of that specific error can mean?

@fhinkel
Copy link
Contributor

fhinkel commented Dec 7, 2020

Greetings, we're closing this. Looks like the issue got resolved. Please let us know if the issue needs to be reopened.

@fhinkel fhinkel closed this as completed Dec 7, 2020
@fhinkel fhinkel assigned fhinkel and unassigned sofisl Dec 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs more info This issue needs more information from the customer to proceed. type: question Request for information or clarification. Not an issue.
Projects
None yet
Development

No branches or pull requests

4 participants