Question

I want to use data.photos.service.PhotosService to push and pull photos from Picasa. I got a service key file XXXXXXXX-privatekey.p12 from Google console and am now trying to authenticate using said key with google.

The documentation for OAUTH2 using appengine has led me to believe that using the following would be of use:

f = file(settings.SITE_ROOT + '/aurora/' + settings.PRIVATE_KEY, 'rb')
key = f.read()
f.close()

credentials = SignedJwtAssertionCredentials(settings.SERVICE_ACCOUNT_NAME, key, scope = 'http://picasaweb.google.com/data https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile')
http = httplib2.Http()
http = credentials.authorize(http)
service = build("oauth2", "v2", http=http)
user_info = None
try:
  user_info = service.userinfo().get().execute()
  # neither of these two methods work
  #gd_client.SetOAuthInputParameters(signature_method = gdata.auth.OAuthSignatureMethod.RSA_SHA1, consumer_key = "asdfasdfasdf.apps.googleusercontent.com", rsa_key = key, two_legged_oauth = True, requestor_id = user_info.get('email'))
  #gd_client.auth_token = gdata.gauth.TwoLeggedOAuthRsaToken(consumer_key = user_info.get('email'), rsa_private_key = key, requestor_id = user_info.get('email'))
except errors.HttpError, e:
  logging.error('An error occurred: %s', e)

user_inf0 = {u'verified_email': True, u'id': u'1234', u'name': u'asdfasdfasdf@developer.gserviceaccount.com', u'email': u'asdfasdfasdf@developer.gserviceaccount.com'}

The issue is that either method 1 using SetOAuthInputParameters returns a invalid token, or method 2 returns a 403 restricted.

I am at my wits' end reading through mountains of code that all do regular 3 legged oauth when I really and truly do not want to do it that way. Any ideas/articles I haven't seen yet?

Was it helpful?

Solution

Use gdata.gauth.OAuth2TokenFromCredentials.

auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
gd_client = auth2token.authorize(gd_client)

OAuth2TokenFromCredentials is designed to help you use apiclient and gdata at the same time. Under the covers, it uses the credentials for making sure it has the auth information it needs to perform gdata calls.

Note, if you still get 403, it may be something else entirely. I was using a service account to access a user's data and was getting 403 because I hadn't spec'd the user properly in the SignedJwtAssertionCredentials call.

UPDATE: Here's the basic pattern I used:

from oauth2client.client import SignedJwtAssertionCredentials
credentials = SignedJwtAssertionCredentials(
    "XXXXXXXXXXX@developer.gserviceaccount.com",
    open("keyfile").read(),
    scope=(
        "https://www.googleapis.com/auth/drive",
        "https://spreadsheets.google.com/feeds",
        "https://docs.google.com/feeds"
    ), # For example.
    sub="user@gmail.com"
)
http = httplib2.Http()
http = credentials.authorize(http) # Not needed? See comment below.
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
gd_client = gdata.photos.service.PhotosService() # For example.
gd_client = auth2token.authorize(gd_client)

OTHER TIPS

If you are using MFA on your google account, you need to use the consent screen authentication method. With Picassa API, it does not work as is, as the request API is slightly different.

import gdata.gauth
import os
import pickle
import gdata.photos.service

clientid='xxx'  # https://console.developers.google.com/apis/credentials
clientsecret='xxx'
Scope='https://picasaweb.google.com/data/'
User_agent='myself'

def GetAuthToken():
    if os.path.exists(".token"):
        with open(".token") as f:
            token = pickle.load(f)
    else:
        token = gdata.gauth.OAuth2Token(client_id=clientid,client_secret=clientsecret,scope=Scope,user_agent=User_agent)
        print token.generate_authorize_url(redirect_uri='urn:ietf:wg:oauth:2.0:oob')
        code = raw_input('What is the verification code? ').strip()
        token.get_access_token(code)
        with open(".token", 'w') as f:
            pickle.dump(token, f)
    return token


token = GetAuthToken()

gd_client = gdata.photos.service.PhotosService()
old_request = gd_client.request


def request(operation, url, data=None, headers=None):
    headers = headers or {}
    headers['Authorization'] = 'Bearer ' + token.access_token
    return old_request(operation, url, data=data, headers=headers)


gd_client.request = request
photos = gd_client.GetUserFeed(kind='photo', limit='10')
for photo in photos.entry:
    print 'Recently added photo title:', photo.title.text
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top