Tornado API#

Tornado integration for py oidc auth.

Tornado supports asyncio based request handlers. This adapter calls the async base implementation directly.

Install:

pip install py-oidc-auth[tornado]
conda install -c conda-forge py-oidc-auth-tornado

Usage

import tornado.web
import tornado.ioloop
from py_oidc_auth.tornado_auth import TornadoOIDCAuth

auth = TornadoOIDCAuth(
    client_id="my client",
    discovery_url="https://idp.example.org/realms/demo/.well-known/openid-configuration",
    scopes="myscope profile email",
    broker_mode=True,
    broker_store_url="postgresql+asyncpg://user:pw@db/myapp",
)

class ProtectedHandler(tornado.web.RequestHandler):
    @auth.required()
    async def get(self, token):
        self.write({"sub": token.sub})

app = tornado.web.Application(
    auth.get_auth_routes(prefix="/api") + [(r"/protected", ProtectedHandler)]
)
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
class py_oidc_auth.tornado_auth.TornadoOIDCAuth(client_id: str = '', discovery_url: str = '', client_secret: str | None = None, scopes: str = 'profile email', audience: str | None = None, appname: str = 'py-oidc-auth', proxy: str = '', claims: Dict[str, Any] | None = None, offline_access: bool = True, timeout_sec: int = 10, jwks_uri: str | None = None, issuer: str | None = None, broker_mode: bool = False, broker_store_url: str | None = None, broker_store_obj: BrokerStore | None = None, broker_audience: str = 'py-oidc-auth', trusted_issuers: list[str] | None = None, broker_jwks_path: str = '/auth/v2/.well-known/jwks.json')#

Reusable OpenID Connect helper for Tornado.

Use required() and optional() as decorators for handler methods. Use get_auth_routes() to add standard auth endpoints. When broker_mode=True the decorators verify broker JWTs and the token handler issues broker JWTs instead of passing IDP tokens through.

required(claims: Dict[str, Any] | None = None, scopes: str = '') Callable[[F], F]#

Enforce authentication.

The decorated method receives IDToken as an extra argument.

Parameters:
  • claims – Optional claim constraints.

  • scopes – Space separated scope names.

Returns:

Decorator for Tornado handler methods.

Example

class MyHandler(tornado.web.RequestHandler):
    @auth.required(scopes="admin")
    async def get(self, token):
        self.write({"sub": token.sub})
optional(claims: Dict[str, Any] | None = None, scopes: str = '') Callable[[F], F]#

Allow anonymous access.

The decorated method receives IDToken or None as an extra argument.

Parameters:
  • claims – Optional claim constraints (passthrough mode only).

  • scopes – Space separated scope names.

Returns:

Decorator for Tornado handler methods.

get_auth_routes(prefix: str = '', login: str = '/auth/v2/login', callback: str = '/auth/v2/callback', token: str = '/auth/v2/token', device_flow: str | None = '/auth/v2/device', logout: str | None = '/auth/v2/logout', userinfo: str | None = '/auth/v2/userinfo', jwks: str | None = '/auth/v2/.well-known/jwks.json') List[Tuple[str, Type[tornado.web.RequestHandler], Dict[str, Any]]]#

Return Tornado routes implementing the standard auth endpoints.

The return value is a list of (pattern, handler_class, init_kwargs) tuples.

Parameters:
  • prefix – URL prefix for all routes.

  • login – Path for login.

  • callback – Path for callback.

  • token – Path for token exchange / broker JWT issuance.

  • device_flow – Path for starting the device flow.

  • logout – Path for logout.

  • userinfo – Path for userinfo.

  • userinfo – Path for userinfo (passthrough mode only).

Returns:

List of Tornado route tuples.

Raises:

ValueError – When broker_mode=True and token is falsy.

Request example

GET /auth/v2/login?redirect_uri=https%3A%2F%2Fapp.example.org%2Fcallback HTTP/1.1
Host: app.example.org