OAuth2

Ferris provides utilities for interacting with Google’s implementation of OAuth2, giving the developer easy ways to initiate web server flow, get user credentials, and utilize service accounts.

This documentation assumes you have an understanding of OAuth2. If you’d like to read more on the subject of OAuth2 and how Google uses it please read Google’s documentation.

Configuration

In order to use Ferris’ OAuth2 features, you must first configure client settings in app/settings.py or use the Settings plugin:

app_config['oauth2'] = {
    'client_id': 'XXXXXXXXXXXXXXX.apps.googleusercontent.com',
    'client_secret': 'XXXXXXXXXXXXXXX',
    'developer_key': 'XXXXXXXXXXXXXXX'
}

You can generate your own Client ID and Secret at the Google API Console.

Example

A quick example of how to use the OAuth2 features to interact with a Google API:

from ferris import Controller
from ferris.components import oauth
from apiclient.discovery import build


class Example(Controller):
    class Meta:
        components = (oauth.OAuth,)
        oauth_scopes = ['https://www.googleapis.com/auth/userinfo.profile']

    # Require credentials for the current user with the scopes listed above.
    @oauth.require_credentials
    def list(self):

        # Signed HTTP instance.
        http = self.oauth.http()

        # Access to Google's OAuth info API
        service = build('oauth2', 'v2', http=http)

        user_info = service.userinfo().get().execute()

        return "Hello, you are: %s" % user_info['name']

This example uses the Google user info service to create a friendly message. When you first navigate to /example, you’ll be taken through the entire OAuth Flow. You will only have to complete this once, as it stores the credentials for subsequence requests.

The OAuth Component

class ferris.components.oauth.OAuth(controller)[source]

The OAuth component handles providing credentials to your handler’s actions and automatically initiating the flow to acquire credentials if needed.

As in the example above, to use the component add it to the component list and be sure to specify the needed scopes using Meta.oauth_scopes:

class Example(Controller):
    class Meta:
        components = (oauth.OAuth,)
        oauth_scopes = ['https://www.googleapis.com/auth/userinfo.profile']

You must decorate every action that needs credentials with either @require_credentials, @provide_credentials, or @require_admin_credentials:

@oauth.require_credentials
def list(self):
    http = self.oauth.http()
    ...

@route
@oauth.provide_credentials
def test(self):
    if not self.oauth.has_credentials():
        return "No credentials"
    ...
ferris.components.oauth.require_credentials(method)[source]

Requires that valid credentials exist for the current user before executing the controller. Will redirect the user for authorization. User controller.oauth_scopes to specify which scopes are required.

ferris.components.oauth.provide_credentials(method)[source]

Similar to require_credentials() but instead of automatically redirecting the user when credentials are required it allows you to take your own action.

You can use OAuth.has_credentials() to interrogate.

Admin Credentials

Sometimes you need to use one account for every user without using a service account. You can achieve this using admin credentials. These credentials can only be created by an administrator of an application but will be available for all requests to use.

ferris.components.oauth.require_admin_credentials(method)[source]

Requires that valid credentials exist for the administrator before executing the controller. Will redirect the user for authorization if the user is an admin.

To create admin credentials use the OAuthManager plugin (enabled by default) located at /admin/oauth_manager <http://localhost:8080/admin/oauth_manager>.

Using Credentials

Usually you’ll want an http object that’s signed with the credentials:

OAuth.http()[source]

Returns a signed httplib2.Http instance that can be readily used for making authorized requests.

You can use this to build a service object:

http = self.oauth.http()
service = build('oauth2', 'v2', http=http)

Sometimes you want access to the credentials object directly:

OAuth.credentials()[source]

Returns an Oauth2Credentials object that can be used to sign a request

To check if the credentials exist and are valid, you can use:

OAuth.has_credentials()[source]

Returns true if credentials exist for the current user.

If you want to request that the user grant you access (if you’re using provide instead of require) redirect them to the result of:

OAuth.authorization_url(redirect=None, admin=False, force_prompt=False)[source]

Generates an authorization url to start the OAuth flow for the current user.

Finding Credentials

Sometimes you need to use credentials outside of a controller context (such as in a task). You can find credentials using find_credentials.

ferris.core.oauth2.find_credentials(user=None, scopes=None, admin=None)

Finds credentials that fit the criteria provided. If no user is provided, the first set of credentials that have the given scopes and privilege level.

Returns None if no credentials are found.

Example:

import httplib2
from ferris.core.oauth2 import find_credentials

creds = find_credentials(scopes=["https://www.googleapis.com/drive/file"], admin=True)
http = httplib2.Http()
creds.credentials.authorize(http)

The Oauth Manager

The OAuth Manager plugin allows you to view, add, and delete credentials from the admin interface. Enable it in app/routes.py:

plugins.enable('oauth_manager')

Once enabled, you can access it via /admin/oauth_manager.

OAuth2 Service Accounts

The included OAuth2 Service Account plugin can help you when using Google’s Service Account Flow.

To use, configure the following settings:

settings['oauth2_service_account'] = {
    'client_email': None,  # ..@developer.gserviceaccount.com
    'private_key' None,  # The private key in PEM format
    'developer_key': None
}

By default, Google gives you the private key in pkcs12 (p12) format. For use with App Engine this key must be in PEM format. To convert from pkcs12 to PEM use this command on Linux / OS X:

openssl pkcs12 -in key.p12 -out key.pem -nodes -nocerts

There are equivalent utilities for Windows.

Now you’re ready to go.

ferris.core.oauth2.build_credentials(scope, user=None)

Builds service account credentials using the configuration stored in settings and masquerading as the provided user.

Example:

credentials = build_credentials(
    scope=["https://www.googleapis.com/drive/file"],
    user="user@domain.com")

credentials.authorize(http)

Warning

Service account credentials will not work properly on local development environments that are missing the PyCrypto or PyOpenSSL modules. If you get errors concerning SignedJwtCredentials check your Python installation.

Note

Ferris ensures that the access token is stored in the datastore/memcache to reduce calls to Google’s authorization service and avoid quota issues.