Question

Just started playing with Tornado and want to offer multiple methods of authentication. Currently my app is working fine with Google's hybrid OpenID/oAuth using tornado.auth.GoogleMixin and the unauthenticated users are automatically sent to Google's auth page.

If an unauthenticated user wants to use another option (ie. local auth or tornado.auth.TwitterMixin), how can I implement the logic to choose an auth mechanism within the login handler?

I added the decorator 'tornado.web.authenticated' to all of my exposed methods, and here is the my login handler class (pretty much straight from the Tornado examples) which is currently working with Google OpenID/oAuth:

class AuthLoginHandler(BaseHandler, 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

        ## redirect after auth
        self.authenticate_redirect()

    def _on_auth(self, user):
        ## auth fail
        if not user:
            raise tornado.web.HTTPError(500, 'Google auth failed')

        ## auth success
        identity = self.get_argument('openid.identity', None)

        ## set identity in cookie
        self.set_secure_cookie('identity', tornado.escape.json_encode(identity))
        self.redirect('/')

Appreciate any suggestions for a solution. Thanks

Was it helpful?

Solution

I think the easiest way to do it would be to change the AuthLoginHandler to something more specific, like GoogleAuthHandler, and create an appropriate route for that:

(r"/login/google/", GoogleAuthHandler),
(r"/login/facebook/", FacebookAuthHandler),

etc.

Then simply create links to each authentication provider on the page ala:

<a href="/login/google/>Login with Google</a>
<a href="/login/facebook/">Login with Facebook</a>

If you wanted to make it fancier, you could provide the providers as a select box, or if you wanted to get REALLY fancy, you could parse their 'openid' URL (e.g., if username.google.com, self.redirect("/login/google"), but that assumes that users know their OpenID provider URLs, which is usually not the case. I'd guess if you gave them a google / facebook / twitter icon or something to click on that would confuse the least number of people.

OTHER TIPS

I came upon this problem myself but in a slightly different circumstance.

One solution is actually to do something like this.

class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin, tornado.auth.TwitterMixin):

    def get(self):
        if want_google:
            tornado.auth.GoogleMixin.get_authenticated_user(self)
            #...
        elif want_twitter:
            tornado.auth.TwitterMixin.get_authenticated_user(self)
        #...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top