I am new to Tornado and trying to get simple OAuth twitter authentication working. As per the documention, I need to set up an authentication handler as follows:
class TwitterAuthHandler(BaseHandler, tornado.auth.TwitterMixin):
@tornado.web.asynchronous
@tornado.gen.coroutine
def get(self):
if self.get_argument("oauth_token", None):
user = yield self.get_authenticated_user()
if not user:
raise tornado.web.HTTPError(500, "Twitter auth failed")
self.set_secure_cookie("twitter_user", user)
self.redirect("/")
else:
self.authenticate_redirect()
However, when I run this code I get the error:
File "/Library/Python/2.7/site-packages/tornado/web.py", line 485, in redirect
raise Exception("Cannot redirect after headers have been written")
Exception: Cannot redirect after headers have been written
This seems to be since the asynchronous call is not operating correctly, with the exception raised on the self.authenticate_redirect()
line. If I replace @tornado.gen.coroutine
with @tornado.gen.engine
everything works fine. However, I understand that gen.engine
is the old way of doing things, and gen.coroutine
should be preferred as it returns a future.
I've also tried wrapping the call to self.get_authenticated_user()
in tornado.gen.Task()
. Am not sure when wrapping with gen.Task()
is even necessary, but this does not seem to make any difference in this case.
What is wrong with this code, and why does gen.coroutine
fail but gen.engine
work?