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

Implementations of various third-party authentication schemes.

All the classes in this file are class Mixins designed to be used with web.py RequestHandler classes. The primary methods for each service are authenticate_redirect(), authorize_redirect(), and get_authenticated_user(). The former should be called to redirect the user to, e.g., the OpenID authentication page on the third party service, and the latter should be called upon return to get the user data from the data returned by the third party service.

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 GoogleHandler(tornado.web.RequestHandler, tornado.auth.GoogleMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("openid.mode", None):
            self.get_authenticated_user(self.async_callback(self._on_auth))
            return
        self.authenticate_redirect()

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

Common protocols

class tornado.auth.OpenIdMixin[source]

Abstract implementation of OpenID and Attribute Exchange.

See GoogleMixin below for example implementations.

authenticate_redirect(callback_uri=None, ax_attrs=['name', 'email', 'language', 'username'])[source]

Returns the authentication URL for this service.

After authentication, the service will redirect back to the given callback URI.

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.

get_authenticated_user(callback, http_client=None)[source]

Fetches the authenticated user data upon redirect.

This method should be called by the handler that receives the redirect from the authenticate_redirect() or authorize_redirect() methods.

class tornado.auth.OAuthMixin[source]

Abstract implementation of OAuth.

See TwitterMixin and FriendFeedMixin below for example implementations.

authorize_redirect(callback_uri=None, extra_params=None, http_client=None)[source]

Redirects the user to obtain OAuth authorization for this service.

Twitter and FriendFeed both require that you register a Callback URL with your application. You should call this method to log the user in, and then call get_authenticated_user() in the handler you registered as your Callback URL to complete the authorization process.

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

get_authenticated_user(callback, http_client=None)[source]

Gets the OAuth authorized user and access token on callback.

This method should be called from the handler for your registered OAuth Callback URL to complete the registration process. We call callback with the authenticated user, which in addition to standard attributes like ‘name’ includes the ‘access_key’ attribute, which contains the OAuth access you can use to make authorized requests to this service on behalf of the user.

class tornado.auth.OAuth2Mixin[source]

Abstract implementation of OAuth v 2.

authorize_redirect(redirect_uri=None, client_id=None, client_secret=None, extra_params=None)[source]

Redirects the user to obtain OAuth authorization for this service.

Some providers require that you register a Callback URL with your application. You should call this method to log the user in, and then call get_authenticated_user() in the handler you registered as your Callback URL to complete the authorization process.

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 TwitterHandler(tornado.web.RequestHandler,
                     tornado.auth.TwitterMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("oauth_token", None):
            self.get_authenticated_user(self.async_callback(self._on_auth))
            return
        self.authorize_redirect()

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

The user object returned by get_authenticated_user() includes the attributes ‘username’, ‘name’, and all of the custom Twitter user attributes describe at http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-users%C2%A0show 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 twitter_request().

authenticate_redirect(callback_uri=None)[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.

twitter_request(path, callback, access_token=None, post_args=None, **args)[source]

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

The path should not include the format (we automatically append ”.json” and parse the JSON output).

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://apiwiki.twitter.com/Twitter-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.TwitterMixin):
    @tornado.web.authenticated
    @tornado.web.asynchronous
    def get(self):
        self.twitter_request(
            "/statuses/update",
            post_args={"status": "Testing Tornado Web Server"},
            access_token=user["access_token"],
            callback=self.async_callback(self._on_post))

    def _on_post(self, new_entry):
        if not new_entry:
            # Call failed; perhaps missing permission?
            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 FriendFeedHandler(tornado.web.RequestHandler,
                        tornado.auth.FriendFeedMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("oauth_token", None):
            self.get_authenticated_user(self.async_callback(self._on_auth))
            return
        self.authorize_redirect()

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

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(path, callback, access_token=None, post_args=None, **args)[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.web.asynchronous
    def get(self):
        self.friendfeed_request(
            "/entry",
            post_args={"body": "Testing Tornado Web Server"},
            access_token=self.current_user["access_token"],
            callback=self.async_callback(self._on_post))

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

Google

class tornado.auth.GoogleMixin[source]

Google Open ID / OAuth authentication.

No application registration is necessary to use Google for authentication or to access Google resources on behalf of a user. To authenticate with Google, redirect with authenticate_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 GoogleHandler(tornado.web.RequestHandler, tornado.auth.GoogleMixin):
   @tornado.web.asynchronous
   def get(self):
       if self.get_argument("openid.mode", None):
           self.get_authenticated_user(self.async_callback(self._on_auth))
           return
    self.authenticate_redirect()

    def _on_auth(self, user):
        if not user:
            raise tornado.web.HTTPError(500, "Google auth failed")
        # Save the user with, e.g., set_secure_cookie()
authorize_redirect(oauth_scope, callback_uri=None, ax_attrs=['name', 'email', 'language', 'username'])[source]

Authenticates and authorizes for the given Google resource.

Some of the available resources are:

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

get_authenticated_user(callback)[source]

Fetches the authenticated user data upon redirect.

Facebook

class tornado.auth.FacebookMixin[source]

Facebook Connect authentication.

New applications should consider using FacebookGraphMixin below instead of this class.

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.async_callback(self._on_auth))
            return
        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(callback_uri=None, cancel_uri=None, extended_permissions=None)[source]

Authenticates/installs this app for the current user.

authorize_redirect(extended_permissions, callback_uri=None, cancel_uri=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().

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.async_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)
class tornado.auth.FacebookGraphMixin[source]

Facebook authentication using the new Graph API and OAuth2.

get_authenticated_user(redirect_uri, client_id, client_secret, code, callback, extra_fields=None)[source]

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

Example usage:

class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin):
  @tornado.web.asynchronous
  def get(self):
      if self.get_argument("code", False):
          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"),
            callback=self.async_callback(
              self._on_login))
          return
      self.authorize_redirect(redirect_uri='/auth/facebookgraph/',
                              client_id=self.settings["facebook_api_key"],
                              extra_params={"scope": "read_stream,offline_access"})

  def _on_login(self, user):
    logging.error(user)
    self.finish()
facebook_request(path, callback, access_token=None, post_args=None, **args)[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.web.asynchronous
    def get(self):
        self.facebook_request(
            "/me/feed",
            post_args={"message": "I am posting from my Tornado application!"},
            access_token=self.current_user["access_token"],
            callback=self.async_callback(self._on_post))

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