views:

1290

answers:

5

Hi,

I am trying to get Oauth working with the Google API using Python. I have tried different oauth libraries such as oauth, oauth2 and djanog-oauth but I cannot get it to work (including the provided examples).

For debugging Oauth I use Google's Oauth Playground and I have studied the API and the Oauth documentation

With some libraries I am struggling with getting a right signature, with other libraries I am struggling with converting the request token to an authorized token. What would really help me if someone can show me a working example for the Google API using one of the above-mentioned libraries.

EDIT: My initial question did not lead to any answers so I have added my code. There are two possible causes of this code not working:
1) Google does not authorize my request token, but not quite sure how to detect this
2) THe signature for the access token is invalid but then I would like to know which oauth parameters Google is expecting as I am able to generate a proper signature in the first phase.

This is written using oauth2.py and for Django hence the HttpResponseRedirect.

REQUEST_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetRequestToken'
AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken'
ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken'

CALLBACK = 'http://localhost:8000/mappr/mappr/oauth/' #will become real server when deployed

OAUTH_CONSUMER_KEY = 'anonymous'
OAUTH_CONSUMER_SECRET = 'anonymous'

signature_method = oauth.SignatureMethod_HMAC_SHA1()
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY, secret=OAUTH_CONSUMER_SECRET)
client = oauth.Client(consumer)

request_token = oauth.Token('','') #hackish way to be able to access the token in different functions, I know this is bad, but I just want it to get working in the first place :)

def authorize(request):
    if request.GET == {}:
        tokens = OAuthGetRequestToken()
        return HttpResponseRedirect(AUTHORIZATION_URL + '?' + tokens)
    elif request.GET['oauth_verifier'] != '':
        oauth_token = request.GET['oauth_token']
        oauth_verifier = request.GET['oauth_verifier']
        OAuthAuthorizeToken(oauth_token)
        OAuthGetAccessToken(oauth_token, oauth_verifier)
        #I need to add a Django return object but I am still debugging other phases.

def OAuthGetRequestToken():
    print '*** OUTPUT OAuthGetRequestToken ***'
    params = {
    'oauth_consumer_key': OAUTH_CONSUMER_KEY, 
    'oauth_nonce':  oauth.generate_nonce(),
    'oauth_signature_method': 'HMAC-SHA1',
    'oauth_timestamp': int(time.time()), #The timestamp should be expressed in number of seconds after January 1, 1970 00:00:00 GMT.
    'scope': 'https://www.google.com/analytics/feeds/',
    'oauth_callback': CALLBACK,
    'oauth_version': '1.0'
    }

    # Sign the request.
    req = oauth.Request(method="GET", url=REQUEST_TOKEN_URL, parameters=params)
    req.sign_request(signature_method, consumer, None)

    tokens =client.request(req.to_url())[1]
    params = ConvertURLParamstoDictionary(tokens)
    request_token.key  = params['oauth_token']
    request_token.secret =  params['oauth_token_secret']
    return tokens

def OAuthAuthorizeToken(oauth_token):
    print '*** OUTPUT OAuthAuthorizeToken ***'
    params ={
    'oauth_token' :oauth_token,
    'hd': 'default'
    }
    req = oauth.Request(method="GET", url=AUTHORIZATION_URL, parameters=params)
    req.sign_request(signature_method, consumer, request_token)
    response =client.request(req.to_url())
    print response #for debugging purposes

def OAuthGetAccessToken(oauth_token, oauth_verifier):
    print '*** OUTPUT OAuthGetAccessToken ***'
    params = {
    'oauth_consumer_key':  OAUTH_CONSUMER_KEY,
    'oauth_token': oauth_token,
    'oauth_verifier': oauth_verifier,
    'oauth_token_secret': request_token.secret,
    'oauth_signature_method': 'HMAC-SHA1',
    'oauth_timestamp': int(time.time()),
    'oauth_nonce': oauth.generate_nonce(),
    'oauth_version': '1.0',    
    }

    req = oauth.Request(method="GET", url=ACCESS_TOKEN_URL, parameters=params)
    req.sign_request(signature_method, consumer, request_token)

    response =client.request(req.to_url())
    print response
    return req

def ConvertURLParamstoDictionary(tokens):
    params = {}
    tokens = tokens.split('&')
    for token in tokens:
        token = token.split('=')
        params[token[0]] = token[1]

    return params
A: 

This may be the answer.

When calling OAuthGetRequestToken you sign the base_string with your consumer_secret followed by an & (ampersand)

When calling OAuthGetAccessToken you sign the base_string with your consumer_secret followed by an & (ampersand) followed by token_secret.

You would sign the base_string using (consumer_secret + "&") for OAuthGetRequestToken and you would sign the base_string using (consumer_secret + "&" + token_secret) for OAuthGetAccessToken

http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iii-security-architecture/ In the PLAINTEXT and HMAC-SHA1 methods, the shared secret is the combination of the Consumer Secret and Token Secret.

AlBeebe
A: 

Have you tried the official gdata python api ? It ships with an oauth client and hides the complexity of oauth calls. http://code.google.com/p/gdata-python-client/

Stephane JAIS
A: 

IIRC Google oauth is not quite following the standard, you have to specify what service you're requesting for (look at the examples provided in the google docs) in the request as an additional parameter, or it won't work.

Gabe
+1  A: 

Tornado has working code for Google oauth. Check it out here. google auth. I 've used it and worked pretty well out of the box. All you need to do is pluck out the class and carefully put it into a django view.

PS: Tornado makes use of async module for the user to return. Since you are using django you need to rely on some get variable to identify that a user has just granted access to your application.

Yashh
+2  A: 

I have OAuth working in a python App Engine app:

http://github.com/sje397/Chess

The app is running at:

http://your-move.appspot.com

sje397