|
OAuth2
OAuth 2.0 in the client library
OverviewOAuth 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
RegisteringBefore 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. SampleWeb ApplicationHere 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-LineHere 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 APIOAuth2DecoratorThe 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.pyfrom 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.yamlapplication: api-python-client-doc version: 1 runtime: python api_version: 1 handlers: - url: /oauth2callback script: oauth2client/appengine.py - url: .* script: main.py Required vs AwareOAuth2Decorator 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 AccountsService 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. | |