Google Buzz, OAuth And Python
Google Buzz is a social networking and messaging tool from Google Inc. that’s integrated into GMail. Google Buzz was released in early February this year (9th Feb 2010), and since then it has emerged as an important social network for GMail users, and many people (including me) prefer it now to other social networking platforms such as Facebook.
In May Google revealed the Buzz API to the public so developers around the world could write applications to interact with Google Buzz to read and/or write.
Google uses OAuth for authentication and authorization to their services. OAuth is an open standard that allows users to share their content (or data generally) from one site to another (or to an application generally) without having to hand the other site their credentials. For more information about OAuth Open Standard go here
I was digging around to make a small application to notify me of new Buzzes or new comments on Buzzes, so I searched and read the API to interact with Google Buzz. In this post I’ll share my Python code that uses OAuth to authorize the application to use Google Buzz data, and soon I’ll share my application when it’s done 🙂
The Process
The process of authentication and authorization according to OAuth consists of three steps:
- Asking Google for a
Request Token
. The token is bound to a scope, this scope identifies the interests of your application with the user’s data.
<a id="GoogleBuzzScopes"></a>Google Buzz has two scopes; Full Access scope `https://www.googleapis.com/auth/buzz` and Read Only Scope `https://www.googleapis.com/auth/buzz.readonly`, you must select the scope that suits your needs.
- Asking the user to authorize your needs by redirecting him/her to a page in Google’s website to log in and authorize your application. As a result the user gets a verification code that must be delivered to your application so it can continue to step 3. There are three ways of getting the verification from the user listed here.
- Exchanging the
Request Token
for anAccess Token
that can be used later for authorizing your requests for data. Your application should save this token to use it later, this token has unlimited expiration time, so you don’t need to bother the user with authorization more than once (Unless the user revokes the access of your application from his/her account).
Prerequisites
- My class depends on Python-OAuth2, so you need to download and install it first.
- The code is written using Python 2.6.
General Parameters
All OAuth requests must have the following parameters:
- oauth_version: Which defines the version of OAuth to use (since when writing this post there were only 1.0 and 1.0a I’ll be using 1.0).
- oauth_nonce: A pseudo-random number.
- oauth_timestamp: The timestamp when generating the request.
- oauth_signature_method: The signature method used to sign the base string that identifies the request, which is either
HMAC-SHA1
orRSA-SHA1
(It can bePLAINTEXT
but Google doesn’t support it). - oauth_consumer_key and oauth_consumer_secret: The key and secret of your application, if you have registered your application then you’ll have a pair of key and secret for your application. If you don’t have a registered application you can use
anonymous
for both key and secret. - oauth_signature: Which is generated using the chosen signature method for the base string which identifies the request
So basically we’ll need to add those parameters to every request we make and we’ll have to sign the request. The former is done internally by calling __getParams
, while the latter is done internally by calling __signRequest
for each request.
Getting The Request Token
This request has the following parameters added to the general parameters:
- oauth_callback: The URL that the user would be redirected to after authorizing your application, and when redirected the verification code is passed to this URL as a parameter along other token parameters. If you don’t have a URL or can’t redirect the user for some reasons you can use the special value
oob
(Out Of Bounds) so that Google redirects the user to a page in Google’s website that has the verification code inside it. - scope: The scope you selected for your application from here.
- xoauth_displayname: The friendly name of your application that will Google will use when asking the user to authorize it.
This procedure is done by sending a POST
request to the following URL https://www.google.com/accounts/OAuthGetRequestToken
with the previous parameters while setting the ContentType
header to application/x-www-form-urlencoded
.
The response must be Request Token
data with status code HTTP 200
.
params = self.__getParams() params.update({'oauth_callback' : self.callbackURL, 'scope' : self.defaultScope, 'xoauth_displayname' : self.applicationName}) oauthRequest = oauth.Request(method="POST", url=REQUEST_TOKEN_URL, parameters=params) self.__signRequest(oauthRequest) self.connection.request('POST', REQUEST_TOKEN_URL, body=oauthRequest.to_postdata(), headers={'Content-Type': 'application/x-www-form-urlencoded'}) resp = self.connection.getresponse() if resp.status != 200: raise Exception, "Couldn't get a Request Token, status code: %d." % resp.status self._token = oauth.Token.from_string(resp.read()) self.__destroyConnection()
This method __destroyConnection
is used to destroy the connection because it becomes invalid after a few requests.
Redirecting The User To Authorization Page
Here we’ll have to know what is the URL of the page to redirect the user to, and that’s done by sending a GET
request to the following URL https://www.google.com/buzz/api/auth/OAuthAuthorizeToken
with the following parameters:
- oauth_token: The key of the
Request Token
received in the previous step. - scope: Described earlier.
- domain: The domain that your application uses, this is used for web applications, you must set it to anonymous for desktop applications.
- xoauth_displayname: Described earlier.
The response would be a page with HTTP 302
status code, this page contains the URL to redirect the user to in the location
header.
self.connection.request('GET', AUTHORIZE_TOKEN_URL + '?oauth_token=' + self.token.key + '&scope=' + self.defaultScope + '&domain=anonymous' + '&' + urllib.urlencode({'xoauth_displayname' : self.applicationName}).replace('+', '%20')) resp = self.connection.getresponse() if resp.status != 302: raise Exception, "Couldn't authorize the token, status code: %d." % resp.status url = resp.getheader('location') webbrowser.open(url) self.__destroyConnection()
This method webbrowser.open
is used to open the URL in the web browser of the user, it is -obviously- contained in the webbrowser
Python standard module.
As a result of the authorization Google gives you (or the user) the verification code for the token, after acquiring it (automatically or by asking the user to give it to your application somehow) we give it to the token by calling setTokenVerifier
method.
Exchanging The Request Token For The Access Token
This request has the following parameters added to the general parameters:
- oauth_token: Described earlier.
- oauth_verifier: The verification code acquired from the previous step.
This procedure is done by sending a POST
request with the previous parameters to the following URL https://www.google.com/accounts/OAuthGetAccessToken
.
The result is the Access Token
data in a page with HTTP 200
status code.
params = self.__getParams() params.update({ 'oauth_token' : self.token.key, 'oauth_verifier' : self.token.verifier }) oauthRequest = oauth.Request(method="POST", url=ACCESS_TOKEN_URL, parameters=params) self.__signRequest(oauthRequest) self.connection.request('POST', ACCESS_TOKEN_URL, body=oauthRequest.to_postdata(), headers={'Content-Type': 'application/x-www-form-urlencoded'}) resp = self.connection.getresponse() if resp.status != 200: raise Exception, "Couldn't exchange the token with an Access Token, status code: %d.\nMessage: %s" % (resp.status, resp.read()) self._token = oauth.Token.from_string(resp.read()) self.__destroyConnection()
Authorizing Requests
Authorizing your requests for data is done by adding Authorization
header to your request which includes the OAuth parameters along with the Access Token
data, and by setting the ContentType
header to either application/json
or application/atom+xml
:
params = self.__getParams() params.update({ 'oauth_token' : self.token.key, }) oauthRequest = oauth.Request(method=method, url=url, parameters=params) self.__signRequest(oauthRequest) if isJSON: headers = {'Content-Type': 'application/json'} else: headers = {'Content-Type': 'application/atom+xml'} headers.update(oauthRequest.to_header()) self.connection.request(method, url, body=body, headers=headers) resp = self.connection.getresponse() data = resp.read() self.__destroyConnection() return resp.status, data
Example On Using BuzzOAuth Class
This example uses the BuzzOAuth class to get the list of Buzzes for the user to read (The list of his/her friends’ Buzzes).
from BuzzOAuth import BuzzOAuth boauth = BuzzOAuth() boauth.requestToken() boauth.authorizeToken() boauth.setTokenVerifier(raw_input('Enter the verifier please: ')) boauth.convertToAccessToken() boauth.saveTokenToFile() status, data = boauth.request('GET', 'https://www.googleapis.com/buzz/v1/activities/@me/@consumption?alt=json') print status print "" print data
The method request
uses the Access Token
to do the request passed to it and returns a tuple of the status code and data returned by the request.
In line 8 the call for method saveTokenToFile
saves the Access Token
to a binary file called token.tok
by default, so that the application can later just use this token like this:
from BuzzOAuth import BuzzOAuth boauth = BuzzOAuth() boauth.loadTokenFromFile() status, data = boauth.request('GET', 'https://www.googleapis.com/buzz/v1/activities/@me/@consumption?alt=json') print status print "" print data
Download
You can download this class (BuzzOAuth.py) from here: http://www.box.net/shared/2m9srr12z7
License
This work is licensed under the GNU Public License (GPL). To view a copy of this license, visit http://www.gnu.org/copyleft/gpl.html.