4
votes

I am trying to use the Gmail API with the Python client libraries. However, I am hitting an error message about AccessTokenRefreshError: invalid_grant.

I have installed the Google client libraries as so:

pip install google-api-python-client

I have gone to the Google Developer's Console, created a new Project, then gone to APIs & auth, then Credentials. I then clicked on Create new Client ID, and selected Service account.

At first, when I ran the following, it complained about no crypto library, so I pip installed pycrypto. Then, it complained about the keyfile being in the wrong format, so I pip installed pyopenssl

Then, in an Python shell I run:

from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<SANITISED>.apps.googleusercontent.com'
with open("foobar-d31647e3d00a.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)

It is when I run the last command that I get the following stacktrace:

AccessTokenRefreshError                   Traceback (most recent call last)
<ipython-input-8-7fd72f40edd2> in <module>()
----> 1 gmail_server = build('gmail', 'v1', http=http_auth)

/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/discovery.pyc in build(serviceName, version, http, discoveryServiceUrl, developerKey, model, requestBuilder, credentials)
    196   logger.info('URL being requested: GET %s' % requested_url)
    197
--> 198   resp, content = http.request(requested_url)
    199
    200   if resp.status == 404:

/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/oauth2client/client.pyc in new_request(uri, method, body, headers, redirections, connection_type)
    528       if not self.access_token:
    529         logger.info('Attempting refresh to obtain initial access_token')
--> 530         self._refresh(request_orig)
    531
    532       # Clone and modify the request headers to add the appropriate

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/oauth2client/client.pyc in _refresh(self, http_request)
    742     """
    743     if not self.store:
--> 744       self._do_refresh_request(http_request)
    745     else:
    746       self.store.acquire_lock()

/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/oauth2client/client.pyc in _do_refresh_request(self, http_request)
    805       except (TypeError, ValueError):
    806         pass
--> 807       raise AccessTokenRefreshError(error_msg)
    808
    809   def _revoke(self, http_request):

AccessTokenRefreshError: invalid_grant

Any thoughts on what I'm doing wrong?

1

1 Answers

3
votes

Aha, I found the issue - silliness on my part.

I was using the "Client ID", and passing that into SignedJwtAssertionCredentials

I should have been using the "Email Address", and passing that in instead.

You'd think the fact that the variable was named client_email would have been a clue...haha.

For reference, the relevant API docs page:

http://google-api-python-client.googlecode.com/hg/docs/epy/oauth2client.client.SignedJwtAssertionCredentials-class.html