Author Joe Gasewicz
Published on 03 Apr 2026 21:11:09
rnado has always been one of those frameworks that feels… honest.
No magic. No hidden layers. No pretending async is something it’s not.
But that honesty comes with a tradeoff:
you don’t get everything handed to you.
Sessions are a perfect example.
If you’ve used Django, sessions are built in.
If you’ve used Flask, you grab an extension.
If you’ve used FastAPI, you start wiring dependencies together.
With Tornado?
You build it yourself.
When you log a user in, you need:
a way to identify them (session ID)
a secure way to store that identifier (cookie)
a reliable backend to store session data (Redis)
Tornado gives you secure cookies, which is great.
But it does not give you a full session system.
So you end up writing the same boilerplate over and over.
I got tired of doing that, so I built a small library:
👉 tornado-auth-sessions
It gives you:
Redis-backed sessions
secure cookies (via Tornado)
a simple mixin you can drop into any handler
No frameworks on top of Tornado. Just clean primitives.
The pattern is simple:
Cookie stores a signed session_id
Redis stores:
session:<session_id> -> user_idThat’s it.
No user data in the browser.
No trusting the client.
Everything verified server-side.
First, install:
pip install tornado-auth-sessionsThen configure your Tornado app:
import tornado.web
app = tornado.web.Application(
handlers,
cookie_secret="super-secret-key",
redis_host={
"host": "localhost",
"port": 6379,
"db": 0,
"decode_responses": True,
},
)Create a base handler:
import tornado
from tornado_auth_sessions import TornadoAuthSessionMixin
class BaseHandler(
TornadoAuthSessionMixin,
tornado.web.RequestHandler,
):
passNow every handler inherits session support.
class LoginHandler(BaseHandler):
def post(self):
# validate user...
self.set_session(user.id)
self.redirect("/dashboard")This will:
generate a secure session ID
store it in Redis
set a signed cookie
class DashboardHandler(BaseHandler):
def get(self):
user_id = self.get_session()
if not user_id:
self.redirect("/login")
return
self.write(f"Welcome user {user_id}")class LogoutHandler(BaseHandler):
def post(self):
self.remove_session(user.id)
self.redirect("/")This deletes the session from Redis.
Because sessions should be:
fast
centralized
disposable
Redis gives you:
TTL (sessions expire automatically)
shared state across instances
simple key-value storage
This setup is solid, but don’t forget the basics:
always use HTTPS in production
set secure=True on cookies
use a strong cookie_secret
hash passwords properly (argon2 / bcrypt)
add CSRF protection for forms
You could.
Django gives you everything, but it’s heavy
Flask needs extensions
FastAPI adds abstraction layers
Tornado gives you control.
This library just removes the boring parts while keeping that control intact.
Tornado might not be trendy anymore, but it’s still one of the cleanest ways to build async systems in Python.
And honestly?
Sometimes you don’t want more features.
You just want fewer problems.