Does the Gmail API support using OAuth Service Acc

2019-02-18 20:59发布

问题:

I am trying to use the Gmail API with the Python Google Client library.

I have created a Service Account credential through the Google Developer Console.

I am then attempting to use those credentials like sO:

from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'

with open("foobar-<sanitised>.p12") as f:
    private_key = f.read()
    credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly')

from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)

However, when I try to use the actual Gmail API, I get an HTTP 500 error:

In [13]: threads = gmail_server.users().threads().list(userId='me').execute()
---------------------------------------------------------------------------
HttpError                                 Traceback (most recent call last)
<ipython-input-13-a74134635cc3> in <module>()
----> 1 threads = gmail_server.users().threads().list(userId='me').execute()

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/oauth2client/util.pyc in positional_wrapper(*args, **kwargs)
    133         else: # IGNORE
    134           pass
--> 135       return wrapped(*args, **kwargs)
    136     return positional_wrapper
    137

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/googleapiclient/http.pyc in execute(self, http, num_retries)
    721       callback(resp)
    722     if resp.status >= 300:
--> 723       raise HttpError(resp, content, uri=self.uri)
    724     return self.postproc(resp, content)
    725

HttpError: <HttpError 500 when requesting https://www.googleapis.com/gmail/v1/users/me/threads?alt=json returned "Backend Error">

A user mentioned here that apparently the "Service Accounts" do not support using the GMail API:

https://stackoverflow.com/a/24645874/139137

Is anybody able to confirm if this is the case, or if it's documented by Google anywhere?

My assumption was that since the Service Account credentials were created through a user's Google Developer Console, it would just be associated with that user, and should work fine?

EDIT:

I should also mentioned I did try explicitly adding my client to the "Managing Client API Access" page in the Google Apps Admin Console:

However, I am still getting the HTTP 500 Backend Error.

Also, the help links on that page go to a OAuth 1.0 specific page - I have a suspicion that this page is only for OAuth 1.0, although it's not explicitly mentioned there.

EDIT 2

Also, I should mentioned that I tried using the Google API Explorer at:

https://developers.google.com/apis-explorer/#p/gmail/v1/gmail.users.messages.list?userId=me&_h=1&

using OAuth 2.0 and the interactive user flow, and it works fine (i.e. it lists emails).

EDIT 3

I tried adding the sub argument as suggested by Jay Lee.

On my own Google Apps domain, it does actually work:

from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'
with open('foo-bar-<sanitised>.p12') as f:
    private_key = f.read()
credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly', sub='victorhooi@example.com')
from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)
threads = gmail_server.users().threads().list(userId='me').execute()

And then threads gives me:

In [12]: threads
Out[12]:
{u'nextPageToken': u'00058094761552980977',
 u'resultSizeEstimate': 178,
 u'threads': [{u'historyId': u'8942',
   u'id': u'14abc26f1893823b',
   u'snippet': u''},
  {u'historyId': u'8822', u'id': u'14a4ffc2724e9384', u'snippet': u''},
  {u'historyId': u'8769', u'id': u'14a36a9c6f552af3', u'snippet': u''},
  {u'historyId': u'8716', u'id': u'14a31822f19bb161', u'snippet': u''},
  {u'historyId': u'8671', u'id': u'14a2bee13eb87c07', u'snippet': u''},

However, when I try using the sub argument on my corporate Google Apps domain, when I get to the following line:

gmail_server = build('gmail', 'v1', http=http_auth)

This gives me the error:

AccessTokenRefreshError: access_denied: Requested client not authorized.

I'm fairly certain that client does exist in the Google Developer's console, and the Gmail API is enabled. I'm just not sure why the sub argument triggers that error.

And then, if I try the same code using a different account on the corporate Google Apps domain, that hasn't been Delegated, I get:

AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.

回答1:

Try using:

credentials = SignedJwtAssertionCredentials(client_email, private_key,
  'https://www.googleapis.com/auth/gmail.readonly', sub='user@domain.com')

where user@domain.com is the user you wish to impersonate.