简体   繁体   中英

Why does Gmail API fail with a 403 error, using code that works properly for Google Calendar API?

I'm following these guides: https://developers.google.com/google-apps/calendar/quickstart/python , https://developers.google.com/gmail/api/quickstart/python .

I've completed all the setup steps for both, and the calendar API code works fine, while the Gmail API code fails with a 403 error. What's causing this? What's different between these two APIs?

I've combined the code from these two different examples, so they are sharing as much of the API setup code as possible, to rule out a mistake there.

I've disabled and re-enabled Gmail API in Google Dev Console.

As mentioned here , I've enabled the Contacts and Google+ APIs.

As mentioned here , I've tried all three combinations for Gmail scopes - just the scope from the example, just ' https://mail.google.com/ ', or both.

This answer, as well as several other sources, suggest 'setting the "Referers" to "Any referer allowed"', but there is no page in Dev Console I can find that contains this option. I can add a domain through the "domain verification" tab, but this does not seem to affect anything.

Code:

import httplib2
import os
from pprint import pprint

from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools

import datetime

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None


class GoogleApi(object):
    client_secret_file = 'client_secret.json'
    application_name = 'test_app'

    def __init__(self):
        self.credentials = self.get_credentials()
        self.http = self.credentials.authorize(httplib2.Http())
        self.service = discovery.build(self.api_name, self.api_version, http=self.http)

    def get_credentials(self):
        """Gets valid user credentials from storage.

        If nothing has been stored, or if the stored credentials are invalid,
        the OAuth2 flow is completed to obtain the new credentials.

        Returns:
            Credentials, the obtained credential.
        """
        home_dir = os.path.expanduser('~')
        credential_dir = os.path.join(home_dir, '.credentials')
        if not os.path.exists(credential_dir):
            os.makedirs(credential_dir)
        credential_path = os.path.join(credential_dir,
                                       'test-app.json')

        store = oauth2client.file.Storage(credential_path)
        credentials = store.get()
        if not credentials or credentials.invalid:
            flow = client.flow_from_clientsecrets(self.client_secret_file, self.scopes)
            flow.user_agent = self.application_name
            if flags:
                credentials = tools.run_flow(flow, store, flags)
            else:  # Needed only for compatability with Python 2.6
                credentials = tools.run(flow, store)
            print 'Storing credentials to ' + credential_path
        return credentials


class CalendarApi(GoogleApi):
    scopes = 'https://www.googleapis.com/auth/calendar.readonly'
    api_name = 'calendar'
    api_version = 'v3'

    def get_calendar_ids(self):
        cl = self.service.calendarList().list().execute()
        ids = [x['id'] for x in cl['items']]
        return ids


class GmailApi(GoogleApi):

    scopes = 'https://mail.google.com/'
    #scopes = 'https://www.googleapis.com/auth/gmail.readonly'
    api_name = 'gmail'
    api_version = 'v1'

    def get_labels(self):
        ml = self.service.users().labels().list(userId='me').execute()
        labels = results.get('labels', [])
        return labels


def main():
    cc = CalendarApi()
    ids = cc.get_calendar_ids()
    print(ids)

    m = GmailApi()
    labels = m.get_labels()
    print(labels)


if __name__ == '__main__':
    main()

Current error ("Insufficient Permission"):

Traceback (most recent call last):
  File "gmail_api_test.py", line 92, in <module>
    main()
  File "gmail_api_test.py", line 87, in main
    labels = m.get_labels()
  File "gmail_api_test.py", line 76, in get_labels
    ml = self.service.users().labels().list(userId='me').execute()
  File "/usr/local/lib/python2.7/site-packages/oauth2client/util.py", line 140, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/googleapiclient/http.py", line 729, in execute
    raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/gmail/v1/users/me/labels?alt=json returned "Insufficient Permission">

Error from a previous version of the code ("Access Not Configured. The API (Gmail API) is not enabled for your project. Please use the Google Developers Console to update your configuration."):

Traceback (most recent call last):
  File "gmail_demo.py", line 71, in <module>
    main()
  File "gmail_demo.py", line 59, in main
    results = service.users().labels().list(userId='me').execute()
  File "/usr/local/lib/python2.7/site-packages/oauth2client/util.py", line 142, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/googleapiclient/http.py", line 729, in execute
    raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/gmail/v1/users/me/labels?alt=json returned "Access Not Configured. The API (Gmail API) is not enabled for your project. Please use the Google Developers Console to update your configuration.">

The reason why the permission is still insufficient is because the refresh_token in your file is still valid. The access_token and refresh_token you get when authenticating your users only have the scopes you specify at that time.

Just imagine if that was not the case. You could then ask your users for readonly and later add the all encompassing https://mail.google.com/ -scope and do a lot of additional stuff without the user's consent.

This has been answered more thoroughly here:

How do I get around HttpError 403 Insufficient Permission? (gmail api, python)

Even though your question deals with the google calendar API, the 403 error is similar to many of the google API apps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM