2
\$\begingroup\$

I recently started a project using python-tornado, and needed to implement google OAuth to manage user logins. I struggled getting this working in the context of the project, and decided to abstract it out to a simple working demo. Since it was such a bear to get up and running in the first place, I wanted to seek feedback regarding my specific implementation, to have the best fleshed-out boilerplate I can to quickly get a new project up and running. Any advice regarding performance/security/maintainability are greatly appreciated.

Below is the code, which a working demo can be found on Github.

import os
import tornado.auth
import tornado.autoreload
import tornado.ioloop
import tornado.web
import json

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("user")

class TestHandler(BaseHandler):
    def get(self):
        name = tornado.escape.xhtml_escape(self.current_user)
        print self.get_current_user()
        self.write("Hello, " + name)

class MainHandler(BaseHandler):
    def get(self):
        if not self.current_user:
            self.redirect("/")
            return

class GoogleOAuth2LoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
    @tornado.gen.coroutine
    def get(self):
        if self.get_argument('code', False):
            access = yield self.get_authenticated_user(
                redirect_uri=os.environ['REDIRECT_URI'],
                code=self.get_argument('code'))
            user = yield self.oauth2_request("https://www.googleapis.com/oauth2/v1/userinfo", access_token=access["access_token"])
            self.set_secure_cookie("user", json.dumps(user))
            self.current_user = user
            self.redirect('/test')
        else:
            yield self.authorize_redirect(
            redirect_uri=os.environ['REDIRECT_URI'],
            client_id=os.environ['CLIENT_ID'],
            client_secret=os.environ['CLIENT_SECRET'],
            scope=['profile', 'email'],
            response_type='code',
            extra_params={'approval_prompt': 'auto'}
        )

def make_app():
    settings = {
    'google_oauth' : {
            'key': os.environ['CLIENT_ID'],
            'secret': os.environ['CLIENT_SECRET'],
    },
    'redirect_uri': os.environ['REDIRECT_URI'],
    'login_url': '/',
    'cookie_secret': os.environ['COOKIE_SECRET']
    }
    return tornado.web.Application([
        (r"/", GoogleOAuth2LoginHandler),
        (r"/test", TestHandler)], **settings)

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print "Listening on port 8888"
    tornado.autoreload.start()
    for dir, _, files in os.walk('./'):
        [tornado.autoreload.watch(dir + '/' + f) for f in files if not f.startswith('.')]

    tornado.ioloop.IOLoop.current().start()
\$\endgroup\$
  • \$\begingroup\$ Your indentation seems off at several places. Can you check that the code is displayed exactly like in your editor and edit in the differences, please. \$\endgroup\$ – 409_Conflict Dec 10 '17 at 13:59
  • \$\begingroup\$ Thank you, it was just the one method from a bad copy and paste. I updated it to reflect the correct spacing. \$\endgroup\$ – Justin Olson Dec 11 '17 at 19:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.