8
votes

edit: I solved it easily by adding "https://www.googleapis.com/auth/plus.me" to my scopes, but I wanted to start a discussion on this topic and see if anyone else experienced the same issue.

I have a service running on GCP, an app engine that uses Google API. This morning, I've received this "warning" message which threw an 500 error. It has been working fine for the past month and only threw this error today (5 hours prior to this post).

Does anyone know why Google returned an additional scope at the oauth2callback? Any additional insight is very much appreciated. Please let me know if you've seen this before or not. I couldn't find it anywhere.

Exception Type: Warning at /oauth2callback

Exception Value: Scope has changed from "https://www.googleapis.com/auth/userinfo.email" to "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me".

This line threw the error:

flow.fetch_token(
        authorization_response=authorization_response,
        code=request.session["code"])

The return url is https://my_website.com/oauth2callback?state=SECRET_STATE&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/plus.me#

instead of the usual https://my_website.com/oauth2callback?state=SECRET_STATE&scope=https://www.googleapis.com/auth/userinfo.email#

edit: sample code

import the required things

SCOPES = ['https://www.googleapis.com/auth/userinfo.email',
          'https://www.googleapis.com/auth/calendar',
          # 'https://www.googleapis.com/auth/plus.me' <-- without this, it throws the error stated above. adding it, fixes the problem. Google returns an additional scope (.../plus.me) which causes an error.
          ]

def auth(request):
    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        CLIENT_SECRETS_FILE, scopes=SCOPES)
    flow.redirect_uri = website_url + '/oauth2callback'
    authorization_url, state = flow.authorization_url(
        access_type='offline', include_granted_scopes='true', 
prompt='consent')
    request.session["state"] = state
    return redirect(authorization_url)

def oauth2callback(request):
    ...
    # request.session["code"] = code in url
    authorization_response = website_url + '/oauth2callback' + parsed.query
    flow.fetch_token(
    authorization_response=authorization_response,
    code=request.session["code"])
    ...
5
Any recent code changes ?Umair Mohammad
What API are you calling and what method?ScottMcC
Please edit your question and include a stackoverflow.com/help/mcveDaImTo
@Umair there was no code changes.Julius Ting
@ScottMcC the error was thrown before calling the api "googleapis.com/userinfo/v2/me"Julius Ting

5 Answers

4
votes

We discovered the same issue today. Our solution has been working without any hiccups for the last couple of months.

We solved the issue by updating our original scopes 'profile email' to https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile and by doing some minor changes to the code.

When initiating the google_auth_oauthlib.flow client, we previously passed in the scopes in a list with only one item which contained a string in which the scopes were separated by spaces.

google_scopes = 'email profile'
self.flow = Flow.from_client_secrets_file(secret_file, scopes=[google_scopes], state=state)

Now, with the updated scopes, we send in a list where each element is a separate scope.

google_scopes = 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile'    
self.flow = Flow.from_client_secrets_file(secret_file, scopes=google_scopes.split(' '), state=state)

Hope it helps, good luck!

1
votes

I am using requests_oauthlib extension and I had the same error. I fix the issue by adding OAUTHLIB_RELAX_TOKEN_SCOPE: '1' to environment variables. So my app.yaml file is similar to this:

#...
env_variables:
  OAUTHLIB_RELAX_TOKEN_SCOPE: '1'
0
votes

At a guess from your error it looks like you're using a depreciated scope. See: https://developers.google.com/+/web/api/rest/oauth#deprecated-scopes

I'm also guessing that you may be using the Google+ Platform Web library and maybe the People:Get method. Perhaps try using one of the following scopes instead:

https://www.googleapis.com/auth/plus.login

or

https://www.googleapis.com/auth/plus.me
0
votes

Given the timing, you might be effected by this change by Google: "Starting July 18, 2017, Google OAuth clients that request certain sensitive OAuth scopes will be subject to review by Google." https://developers.google.com/apps-script/guides/client-verification

0
votes

For my case I added the following line in that function that the authentication is happening in os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1' flow = InstalledAppFlow.from_client_config(client_config, scopes=SCOPES)