tornado.auth — Third-party login with OpenID and OAuth

This module contains implementations of various third-party authentication schemes.

All the classes in this file are class mixins designed to be used with the tornado.web.RequestHandler class. They are used in two ways:

  • On a login handler, use methods such as authenticate_redirect(), authorize_redirect(), and get_authenticated_user() to establish the user’s identity and store authentication tokens to your database and/or cookies.
  • In non-login handlers, use methods such as facebook_request() or twitter_request() to use the authentication tokens to make requests to the respective services.

They all take slightly different arguments due to the fact all these services implement authentication and authorization slightly differently. See the individual service classes below for complete documentation.

Example usage for Google OpenID:

class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
                               tornado.auth.GoogleOAuth2Mixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_argument('code', False):
            user = yield self.get_authenticated_user(
                redirect_uri='http://your.site.com/auth/google',
                code=self.get_argument('code'))
            # Save the user with e.g. set_secure_cookie
        else:
            yield self.authorize_redirect(
                redirect_uri='http://your.site.com/auth/google',
                client_id=self.settings['google_oauth']['key'],
                scope=['profile', 'email'],
                response_type='code',
                extra_params={'approval_prompt': 'auto'})

Changed in version 4.0: All of the callback interfaces in this module are now guaranteed to run their callback with an argument of None on error. Previously some functions would do this while others would simply terminate the request on their own. This change also ensures that errors are more consistently reported through the Future interfaces.

Common protocols

These classes implement the OpenID and OAuth standards. They will generally need to be subclassed to use them with any particular site. The degree of customization required will vary, but in most cases overridding the class attributes (which are named beginning with underscores for historical reasons) should be sufficient.

class tornado.auth.OpenIdMixin[source]

Abstract implementation of OpenID and Attribute Exchange.

See GoogleMixin below for a customized example (which also includes OAuth support).

Class attributes:

  • _OPENID_ENDPOINT: the identity provider’s URI.
authenticate_redirect(*args, **kwargs)[source]

Redirects to the authentication URL for this service.

After authentication, the service will redirect back to the given callback URI with additional parameters including openid.mode.

We request the given attributes for the authenticated user by default (name, email, language, and username). If you don’t need all those attributes for your app, you can request fewer with the ax_attrs keyword argument.

Changed in version 3.1: Returns a Future and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with OAuthMixin.authorize_redirect.

get_authenticated_user(*args, **kwargs)[source]

Fetches the authenticated user data upon redirect.

This method should be called by the handler that receives the redirect from the authenticate_redirect() method (which is often the same as the one that calls it; in that case you would call get_authenticated_user if the openid.mode parameter is present and authenticate_redirect if it is not).

The result of this method will generally be used to set a cookie.

get_auth_http_client()[source]

Returns the AsyncHTTPClient instance to be used for auth requests.

May be overridden by subclasses to use an HTTP client other than the default.

class tornado.auth.OAuthMixin[source]

Abstract implementation of OAuth 1.0 and 1.0a.

See TwitterMixin and FriendFeedMixin below for example implementations, or GoogleMixin for an OAuth/OpenID hybrid.

Class attributes:

  • _OAUTH_AUTHORIZE_URL: The service’s OAuth authorization url.
  • _OAUTH_ACCESS_TOKEN_URL: The service’s OAuth access token url.
  • _OAUTH_VERSION: May be either “1.0” or “1.0a”.
  • _OAUTH_NO_CALLBACKS: Set this to True if the service requires advance registration of callbacks.

Subclasses must also override the _oauth_get_user_future and _oauth_consumer_token methods.

authorize_redirect(*args, **kwargs)[source]

Redirects the user to obtain OAuth authorization for this service.

The callback_uri may be omitted if you have previously registered a callback URI with the third-party service. For some sevices (including Friendfeed), you must use a previously-registered callback URI and cannot specify a callback via this method.

This method sets a cookie called _oauth_request_token which is subsequently used (and cleared) in get_authenticated_user for security purposes.

Note that this method is asynchronous, although it calls RequestHandler.finish for you so it may not be necessary to pass a callback or use the Future it returns. However, if this method is called from a function decorated with gen.coroutine, you must call it with yield to keep the response from being closed prematurely.

Changed in version 3.1: Now returns a Future and takes an optional callback, for compatibility with gen.coroutine.

get_authenticated_user(*args, **kwargs)[source]

Gets the OAuth authorized user and access token.

This method should be called from the handler for your OAuth callback URL to complete the registration process. We run the callback with the authenticated user dictionary. This dictionary will contain an access_key which can be used to make authorized requests to this service on behalf of the user. The dictionary will also contain other fields such as name, depending on the service used.

_oauth_consumer_token()[source]

Subclasses must override this to return their OAuth consumer keys.

The return value should be a dict with keys key and secret.

_oauth_get_user_future(*args, **kwargs)[source]

Subclasses must override this to get basic information about the user.

Should return a Future whose result is a dictionary containing information about the user, which may have been retrieved by using access_token to make a request to the service.

The access token will be added to the returned dictionary to make the result of get_authenticated_user.

For backwards compatibility, the callback-based _oauth_get_user method is also supported.

get_auth_http_client()[source]

Returns the AsyncHTTPClient instance to be used for auth requests.

May be overridden by subclasses to use an HTTP client other than the default.

class tornado.auth.OAuth2Mixin[source]

Abstract implementation of OAuth 2.0.

See FacebookGraphMixin below for an example implementation.

Class attributes:

  • _OAUTH_AUTHORIZE_URL: The service’s authorization url.
  • _OAUTH_ACCESS_TOKEN_URL: The service’s access token url.
authorize_redirect(*args, **kwargs)[source]

Redirects the user to obtain OAuth authorization for this service.

Some providers require that you register a redirect URL with your application instead of passing one via this method. You should call this method to log the user in, and then call get_authenticated_user in the handler for your redirect URL to complete the authorization process.

Changed in version 3.1: Returns a Future and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with OAuthMixin.authorize_redirect.

Google

class tornado.auth.GoogleMixin[source]

Google Open ID / OAuth authentication.

Deprecated since version 4.0: New applications should use GoogleOAuth2Mixin below instead of this class. As of May 19, 2014, Google has stopped supporting registration-free authentication.

No application registration is necessary to use Google for authentication or to access Google resources on behalf of a user.

Google implements both OpenID and OAuth in a hybrid mode. If you just need the user’s identity, use authenticate_redirect. If you need to make requests to Google on behalf of the user, use authorize_redirect. On return, parse the response with get_authenticated_user. We send a dict containing the values for the user, including email, name, and locale.

Example usage:

class GoogleLoginHandler(tornado.web.RequestHandler,
                         tornado.auth.GoogleMixin):
   @tornado.gen.coroutine
   def get(self):
       if self.get_argument("openid.mode", None):
           user = yield self.get_authenticated_user()
           # Save the user with e.g. set_secure_cookie()
       else:
           yield self.authenticate_redirect()
authorize_redirect(*args, **kwargs)[source]

Authenticates and authorizes for the given Google resource.

Some of the available resources which can be used in the oauth_scope argument are:

You can authorize multiple resources by separating the resource URLs with a space.

Changed in version 3.1: Returns a Future and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with OAuthMixin.authorize_redirect.

get_authenticated_user(*args, **kwargs)[source]

Fetches the authenticated user data upon redirect.

class tornado.auth.GoogleOAuth2Mixin[source]

Google authentication using OAuth2.

In order to use, register your application with Google and copy the relevant parameters to your application settings.

  • Go to the Google Dev Console at http://console.developers.google.com
  • Select a project, or create a new one.
  • In the sidebar on the left, select APIs & Auth.
  • In the list of APIs, find the Google+ API service and set it to ON.
  • In the sidebar on the left, select Credentials.
  • In the OAuth section of the page, select Create New Client ID.
  • Set the Redirect URI to point to your auth handler
  • Copy the “Client secret” and “Client ID” to the application settings as {“google_oauth”: {“key”: CLIENT_ID, “secret”: CLIENT_SECRET}}

New in version 3.2.

get_authenticated_user(*args, **kwargs)[source]

Handles the login for the Google user, returning a user object.

Example usage:

class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
                               tornado.auth.GoogleOAuth2Mixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_argument('code', False):
            user = yield self.get_authenticated_user(
                redirect_uri='http://your.site.com/auth/google',
                code=self.get_argument('code'))
            # Save the user with e.g. set_secure_cookie
        else:
            yield self.authorize_redirect(
                redirect_uri='http://your.site.com/auth/google',
                client_id=self.settings['google_oauth']['key'],
                scope=['profile', 'email'],
                response_type='code',
                extra_params={'approval_prompt': 'auto'})
get_auth_http_client()[source]

Returns the AsyncHTTPClient instance to be used for auth requests.

May be overridden by subclasses to use an HTTP client other than the default.

Facebook

class tornado.auth.FacebookGraphMixin[source]

Facebook authentication using the new Graph API and OAuth2.

get_authenticated_user(*args, **kwargs)[source]

Handles the login for the Facebook user, returning a user object.

Example usage:

class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin):
  @tornado.gen.coroutine
  def get(self):
      if self.get_argument("code", False):
          user = yield self.get_authenticated_user(
              redirect_uri='/auth/facebookgraph/',
              client_id=self.settings["facebook_api_key"],
              client_secret=self.settings["facebook_secret"],
              code=self.get_argument("code"))
          # Save the user with e.g. set_secure_cookie
      else:
          yield self.authorize_redirect(
              redirect_uri='/auth/facebookgraph/',
              client_id=self.settings["facebook_api_key"],
              extra_params={"scope": "read_stream,offline_access"})
facebook_request(*args, **kwargs)[source]

Fetches the given relative API path, e.g., “/btaylor/picture”

If the request is a POST, post_args should be provided. Query string arguments should be given as keyword arguments.

An introduction to the Facebook Graph API can be found at http://developers.facebook.com/docs/api

Many methods require an OAuth access token which you can obtain through authorize_redirect and get_authenticated_user. The user returned through that process includes an access_token attribute that can be used to make authenticated requests via this method.

Example usage:

class MainHandler(tornado.web.RequestHandler,
                  tornado.auth.FacebookGraphMixin):
    @tornado.web.authenticated
    @tornado.gen.coroutine
    def get(self):
        new_entry = yield self.facebook_request(
            "/me/feed",
            post_args={"message": "I am posting from my Tornado application!"},
            access_token=self.current_user["access_token"])

        if not new_entry:
            # Call failed; perhaps missing permission?
            yield self.authorize_redirect()
            return
        self.finish("Posted a message!")

The given path is relative to self._FACEBOOK_BASE_URL, by default “https://graph.facebook.com”.

Changed in version 3.1: Added the ability to override self._FACEBOOK_BASE_URL.

get_auth_http_client()[source]

Returns the AsyncHTTPClient instance to be used for auth requests.

May be overridden by subclasses to use an HTTP client other than the default.

class tornado.auth.FacebookMixin[source]

Facebook Connect authentication.

Deprecated since version 1.1: New applications should use FacebookGraphMixin below instead of this class. This class does not support the Future-based interface seen on other classes in this module.

To authenticate with Facebook, register your application with Facebook at http://www.facebook.com/developers/apps.php. Then copy your API Key and Application Secret to the application settings facebook_api_key and facebook_secret.

When your application is set up, you can use this mixin like this to authenticate the user with Facebook:

class FacebookHandler(tornado.web.RequestHandler,
                      tornado.auth.FacebookMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("session", None):
            self.get_authenticated_user(self._on_auth)
            return
        yield self.authenticate_redirect()

    def _on_auth(self, user):
        if not user:
            raise tornado.web.HTTPError(500, "Facebook auth failed")
        # Save the user using, e.g., set_secure_cookie()

The user object returned by get_authenticated_user includes the attributes facebook_uid and name in addition to session attributes like session_key. You should save the session key with the user; it is required to make requests on behalf of the user later with facebook_request.

authenticate_redirect(*args, **kwargs)[source]

Authenticates/installs this app for the current user.

Changed in version 3.1: Returns a Future and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with OAuthMixin.authorize_redirect.

authorize_redirect(extended_permissions, callback_uri=None, cancel_uri=None, callback=None)[source]

Redirects to an authorization request for the given FB resource.

The available resource names are listed at http://wiki.developers.facebook.com/index.php/Extended_permission. The most common resource types include:

  • publish_stream
  • read_stream
  • email
  • sms

extended_permissions can be a single permission name or a list of names. To get the session secret and session key, call get_authenticated_user() just as you would with authenticate_redirect().

Changed in version 3.1: Returns a Future and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with OAuthMixin.authorize_redirect.

get_authenticated_user(callback)[source]

Fetches the authenticated Facebook user.

The authenticated user includes the special Facebook attributes ‘session_key’ and ‘facebook_uid’ in addition to the standard user attributes like ‘name’.

facebook_request(method, callback, **args)[source]

Makes a Facebook API REST request.

We automatically include the Facebook API key and signature, but it is the callers responsibility to include ‘session_key’ and any other required arguments to the method.

The available Facebook methods are documented here: http://wiki.developers.facebook.com/index.php/API

Here is an example for the stream.get() method:

class MainHandler(tornado.web.RequestHandler,
                  tornado.auth.FacebookMixin):
    @tornado.web.authenticated
    @tornado.web.asynchronous
    def get(self):
        self.facebook_request(
            method="stream.get",
            callback=self._on_stream,
            session_key=self.current_user["session_key"])

    def _on_stream(self, stream):
        if stream is None:
           # Not authorized to read the stream yet?
           self.redirect(self.authorize_redirect("read_stream"))
           return
        self.render("stream.html", stream=stream)
get_auth_http_client()[source]

Returns the AsyncHTTPClient instance to be used for auth requests.

May be overridden by subclasses to use an HTTP client other than the default.

Twitter

class tornado.auth.TwitterMixin[source]

Twitter OAuth authentication.

To authenticate with Twitter, register your application with Twitter at http://twitter.com/apps. Then copy your Consumer Key and Consumer Secret to the application settings twitter_consumer_key and twitter_consumer_secret. Use this mixin on the handler for the URL you registered as your application’s callback URL.

When your application is set up, you can use this mixin like this to authenticate the user with Twitter and get access to their stream:

class TwitterLoginHandler(tornado.web.RequestHandler,
                          tornado.auth.TwitterMixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_argument("oauth_token", None):
            user = yield self.get_authenticated_user()
            # Save the user using e.g. set_secure_cookie()
        else:
            yield self.authorize_redirect()

The user object returned by get_authenticated_user includes the attributes username, name, access_token, and all of the custom Twitter user attributes described at https://dev.twitter.com/docs/api/1.1/get/users/show

authenticate_redirect(*args, **kwargs)[source]

Just like authorize_redirect, but auto-redirects if authorized.

This is generally the right interface to use if you are using Twitter for single-sign on.

Changed in version 3.1: Now returns a Future and takes an optional callback, for compatibility with gen.coroutine.

twitter_request(*args, **kwargs)[source]

Fetches the given API path, e.g., statuses/user_timeline/btaylor

The path should not include the format or API version number. (we automatically use JSON format and API version 1).

If the request is a POST, post_args should be provided. Query string arguments should be given as keyword arguments.

All the Twitter methods are documented at http://dev.twitter.com/

Many methods require an OAuth access token which you can obtain through authorize_redirect and get_authenticated_user. The user returned through that process includes an ‘access_token’ attribute that can be used to make authenticated requests via this method. Example usage:

class MainHandler(tornado.web.RequestHandler,
                  tornado.auth.TwitterMixin):
    @tornado.web.authenticated
    @tornado.gen.coroutine
    def get(self):
        new_entry = yield self.twitter_request(
            "/statuses/update",
            post_args={"status": "Testing Tornado Web Server"},
            access_token=self.current_user["access_token"])
        if not new_entry:
            # Call failed; perhaps missing permission?
            yield self.authorize_redirect()
            return
        self.finish("Posted a message!")

FriendFeed

class tornado.auth.FriendFeedMixin[source]

FriendFeed OAuth authentication.

To authenticate with FriendFeed, register your application with FriendFeed at http://friendfeed.com/api/applications. Then copy your Consumer Key and Consumer Secret to the application settings friendfeed_consumer_key and friendfeed_consumer_secret. Use this mixin on the handler for the URL you registered as your application’s Callback URL.

When your application is set up, you can use this mixin like this to authenticate the user with FriendFeed and get access to their feed:

class FriendFeedLoginHandler(tornado.web.RequestHandler,
                             tornado.auth.FriendFeedMixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_argument("oauth_token", None):
            user = yield self.get_authenticated_user()
            # Save the user using e.g. set_secure_cookie()
        else:
            yield self.authorize_redirect()

The user object returned by get_authenticated_user() includes the attributes username, name, and description in addition to access_token. You should save the access token with the user; it is required to make requests on behalf of the user later with friendfeed_request().

friendfeed_request(*args, **kwargs)[source]

Fetches the given relative API path, e.g., “/bret/friends”

If the request is a POST, post_args should be provided. Query string arguments should be given as keyword arguments.

All the FriendFeed methods are documented at http://friendfeed.com/api/documentation.

Many methods require an OAuth access token which you can obtain through authorize_redirect and get_authenticated_user. The user returned through that process includes an access_token attribute that can be used to make authenticated requests via this method.

Example usage:

class MainHandler(tornado.web.RequestHandler,
                  tornado.auth.FriendFeedMixin):
    @tornado.web.authenticated
    @tornado.gen.coroutine
    def get(self):
        new_entry = yield self.friendfeed_request(
            "/entry",
            post_args={"body": "Testing Tornado Web Server"},
            access_token=self.current_user["access_token"])

        if not new_entry:
            # Call failed; perhaps missing permission?
            yield self.authorize_redirect()
            return
        self.finish("Posted a message!")