My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
OAuth2  
OAuth 2.0 in the client library
Updated Mar 20, 2012 by jcgregorio@google.com

Overview

OAuth 2.0 is an emerging standard for accessing protected resources on the web. Google APIs and the google-api-python-client library support OAuth 2.0.

Further Reading

Registering

Before you can use OAuth 2.0, you must register your application using the Google APIs Console. After you've registered, go to the API Access tab and copy the "Client ID" and "Client secret" values, which you'll need later.

If you're writing a web application, then make sure the Redirect URI matches the URI you will use in your application to handle the redirect. For example, the sample below uses the path /auth_return, so if the sample application were hosted at example.com, then you would set the Redirect URI in the APIs Console to be http://example.com/auth_return.

Sample

Web Application

Here is some sample code demonstrating how to do authentication with OAuth 2.0 in a web application. The full code for this sample is in the repository. This sample runs on App Engine and uses the App Engine datastore to store OAuth 2.0 credentials.

from apiclient.discovery import build
from oauth2client.appengine import CredentialsProperty
from oauth2client.appengine import StorageByKeyName
from oauth2client.client import OAuth2WebServerFlow
from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp.util import login_required

class Credentials(db.Model):
  credentials = CredentialsProperty()

The oauth2client module of the library contains helpers to make working with OAuth 2.0 credentials easier. StoreageByKeyName is a helper class that takes care of storing and retrieving OAuth 2.0 credentials to and from the App Engine datastore.

class MainHandler(webapp.RequestHandler):

  @login_required
  def get(self):
    user = users.get_current_user()
    credentials = StorageByKeyName(Credentials, user.user_id(), 'credentials').get()

    if credentials:
      http = httplib2.Http()
      http = credentials.authorize(http)
      p = build("buzz", "v1", http=http)
      # Do stuff with the Buzz API
      # ....
    else:

If we don't find OAuth 2.0 credentials for the user in the datastore, then we need to go through the Web Server Flow to acquire those credentials.

      flow = OAuth2WebServerFlow(
          # Visit https://code.google.com/apis/console to
          # generate your client_id, client_secret and to
          # register your redirect_uri.
          client_id='<YOUR CLIENT ID HERE>',
          client_secret='<YOUR CLIENT SECRET HERE>',
          scope='https://www.googleapis.com/auth/buzz',
          user_agent='buzz-cmdline-sample/1.0')

      callback = self.request.relative_url('/auth_return')
      authorize_url = flow.step1_get_authorize_url(callback)

The flow uses the information provided to give you the URL to redirect the user to, so they can grant the web application access.

      memcache.set(user.user_id(), pickle.dumps(flow))
      self.redirect(authorize_url)

Once the user grants access, they are redirected back to this web application. Credentials are acquired and stored for later use.

class OAuthHandler(webapp.RequestHandler):

  @login_required
  def get(self):
    user = users.get_current_user()
    flow = pickle.loads(memcache.get(user.user_id()))
    if flow:
      credentials = flow.step2_exchange(self.request.params)
      StorageByKeyName(Credentials, user.user_id(), 'credentials').put(credentials)
      self.redirect("/")
    else:
      pass


def main():
  application = webapp.WSGIApplication(
      [
      ('/', MainHandler),
      ('/auth_return', OAuthHandler)
      ],
      debug=True)
  util.run_wsgi_app(application)


if __name__ == '__main__':
  main()

Command-Line

Here is a sample command-line application that uses OAuth 2.0. The full source for this sample is in the repository.

This application is separated into two parts. The first part goes through the steps to acquire and store the token. The oauth2client module contains a helper that does most of the work of the OAuth 2.0 flow. The run function takes an OAuth2WebServerFlow object and the name of a file in which to store the credentials.

import httplib2

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run

def main():
  storage = Storage('moderator.dat')
  credentials = storage.get()

  if credentials is None or credentials.invalid == True:
    flow = OAuth2WebServerFlow(
        client_id='433807057907.apps.googleusercontent.com',
        client_secret='jigtZpMApkRxncxikFpR+SFg',
        scope='https://www.googleapis.com/auth/moderator',
        user_agent='moderator-cmdline-sample/1.0')

    credentials = run(flow, storage)

Now that we have the credentials, we can use them to authorize the HTTP transport. Then we can start interacting with the Google Moderator API, and all the calls will have the OAuth 2.0 credentials applied to them.

  http = httplib2.Http()
  http = credentials.authorize(http)

  p = build("moderator", "v1", http=http)
  # Start doing stuff with the Google Moderator API

OAuth2Decorator

The OAuth2Decorator is a radical simplification for using OAuth 2.0 in an App Engine application. The decorator uses the Flows, Credentials and Storage underneath, but simplifies their usage when we are on a known platform, in this case Google App Engine.

The OAuth2Decorator constructor takes two additional arguments, auth_uri and token_uri, that will default to the Google values, but can be changed so the decorator can be used for non-Google APIs. Also note that you could create more than one decorator object if you needed to, say to Google and Daily Motion.

main.py

from oauth2client.appengine import OAuth2Decorator

decorator = OAuth2Decorator(
  client_id='<YOUR CLIENT ID HERE>',
  client_secret='<YOUR CLIENT SECRET HERE>',
  scope='https://www.googleapis.com/auth/buzz',
  user_agent='buzz-appengine-sample/1.0')

http = httplib2.Http(memcache)
service = build("buzz", "v1", http=http)

class MainHandler(webapp.RequestHandler):

  @decorator.oauth_required
  def get(self):
    http = decorator.http()
    activities = service.activities()
    activitylist = activities.list(scope='@consumption',
                                     userId='@me').execute(http)
    ...

def main():
  application = webapp.WSGIApplication(
      [
      ('/', MainHandler),
      ],
      debug=True)
  util.run_wsgi_app(application)

app.yaml

application: api-python-client-doc
version: 1
runtime: python
api_version: 1


handlers:
- url: /oauth2callback
  script: oauth2client/appengine.py
- url: .*
  script: main.py

Required vs Aware

OAuth2Decorator actually supports two decorators, oauth_required and oauth_aware. Any method decorated with oauth_required will immediately begin the OAuth dance. A method decorated with oauth_aware will get called normally, but with the method the helper methods has_credentials() and authorize_url() can be called. The latter are important for making less a less jarring OAuth experience, letting the user know up front why they are being directed into the OAuth flow before it begins.

Service Accounts

Service Accounts provide certificate-based authentication for server-to-server interactions. This means, for example, that a request from a web application to Google Cloud Storage can be authenticated via a certificate instead of a shared key. Certificates offer better security properties than shared keys and passwords, largely because they are not human-readable or guessable.

To use Service account from Python use SignedJwtAssertionCredentials. There is a sample of using the Tasks API with a Service account.

Note: You will have to install pyOpenSSL to use SignedJwtAssertionCredentials.

Learn more about Service accounts from their announcement.

Powered by Google Project Hosting