Authentication Decorators¶
Authentication decorators provide route-level authentication and authorization controls. These decorators help ensure secure communication and proper authentication for sensitive endpoints.
All examples below assume the following setup exists once at module level:
from tornadoapi_guard import (
SecurityConfig,
SecurityDecorator,
SecurityHandler,
SecurityMiddleware,
)
config = SecurityConfig()
middleware = SecurityMiddleware(config=config)
guard_deco = SecurityDecorator(config)
middleware.set_decorator_handler(guard_deco)
HTTPS Enforcement¶
Force secure connections for specific routes:
. Basic HTTPS Requirement¶
class AuthHttpsHandler(SecurityHandler):
@guard_deco.require_https()
async def post(self) -> None:
self.write({"token": "secure_jwt_token"})
. Combined with Global HTTPS¶
# Global HTTPS enforcement
config = SecurityConfig(enforce_https=True)
class AuthPublicHttpsHandler(SecurityHandler):
@guard_deco.require_https() # Explicit requirement
async def get(self) -> None:
self.write({"data": "definitely secure"})
. HTTPS for Sensitive Operations¶
class AuthPaymentHandler(SecurityHandler):
@guard_deco.require_https()
async def post(self) -> None:
self.write({"status": "payment processed securely"})
class AuthPasswordHandler(SecurityHandler):
@guard_deco.require_https()
async def post(self) -> None:
self.write({"status": "password updated"})
Authentication Requirements¶
Enforce different types of authentication:
. Bearer Token Authentication¶
class AuthBearerHandler(SecurityHandler):
@guard_deco.require_auth(type="bearer")
async def get(self) -> None:
self.write({"profile": "user data"})
. Multiple Authentication Types¶
class AuthAdminHandler(SecurityHandler):
@guard_deco.require_auth(type="bearer")
async def get(self) -> None:
self.write({"admin": "data"})
class AuthServiceHandler(SecurityHandler):
@guard_deco.require_auth(type="basic")
async def get(self) -> None:
self.write({"service": "data"})
. Combined HTTPS and Auth¶
class AuthSecureAdminHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
async def post(self) -> None:
self.write({"data": "doubly secure"})
API Key Authentication¶
Require API keys for endpoint access:
. Basic API Key Requirement¶
class AuthAPIKeyHandler(SecurityHandler):
@guard_deco.api_key_auth(header_name="X-API-Key")
async def get(self) -> None:
self.write({"data": "api key required"})
. Custom Header Names¶
class AuthCustomKeyHandler(SecurityHandler):
@guard_deco.api_key_auth(header_name="X-Custom-Auth")
async def get(self) -> None:
self.write({"data": "custom header auth"})
class AuthServiceKeyHandler(SecurityHandler):
@guard_deco.api_key_auth(header_name="Authorization-Key")
async def get(self) -> None:
self.write({"data": "service authentication"})
. Multiple Key Requirements¶
class AuthDualKeyHandler(SecurityHandler):
@guard_deco.api_key_auth(header_name="X-API-Key")
@guard_deco.api_key_auth(header_name="X-Service-Key")
async def get(self) -> None:
self.write({"data": "dual key authentication"})
Required Headers¶
Enforce specific headers for authentication and security:
. Security Headers¶
class AuthCustomHeadersHandler(SecurityHandler):
@guard_deco.require_headers(
{
"X-Requested-With": "XMLHttpRequest",
"X-CSRF-Token": "required",
}
)
async def get(self) -> None:
self.write({"data": "csrf protected"})
. API Versioning Headers¶
class AuthVersionedHandler(SecurityHandler):
@guard_deco.require_headers(
{
"Accept": "application/vnd.api+json",
"API-Version": "2.0",
}
)
async def get(self) -> None:
self.write({"data": "version 2.0", "format": "json-api"})
. Client Identification¶
class AuthClientHandler(SecurityHandler):
@guard_deco.require_headers(
{
"X-Client-ID": "required",
"X-Client-Version": "required",
"User-Agent": "required",
}
)
async def get(self) -> None:
self.write({"data": "client identified"})
Combined Authentication Patterns¶
Stack multiple authentication decorators for comprehensive security:
. Maximum Security Endpoint¶
class AuthCriticalAdminHandler(SecurityHandler):
@guard_deco.require_https() # Secure connection
@guard_deco.require_auth(type="bearer") # Bearer token
@guard_deco.api_key_auth(header_name="X-Admin-Key") # Admin API key
@guard_deco.require_headers(
{
"X-CSRF-Token": "required", # CSRF protection
"X-Request-ID": "required", # Request tracking
}
)
async def post(self) -> None:
self.write({"status": "critical operation completed"})
. Service-to-Service Authentication¶
class AuthWebhookHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.api_key_auth(header_name="X-Service-Key")
@guard_deco.require_headers(
{
"X-Signature": "required",
"Content-Type": "application/json",
}
)
async def post(self) -> None:
self.write({"status": "webhook processed"})
. Client Application Authentication¶
class AuthMobileHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
@guard_deco.require_headers(
{
"X-App-Version": "required",
"X-Device-ID": "required",
"Accept": "application/json",
}
)
async def get(self) -> None:
self.write({"data": "mobile app data"})
Authentication Flow Examples¶
. Login Endpoint¶
class LoginHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.require_headers(
{
"Content-Type": "application/json",
"X-CSRF-Token": "required",
}
)
async def post(self) -> None:
self.write({"token": "jwt_token", "expires": "3600"})
. Token Refresh¶
class RefreshHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
@guard_deco.require_headers({"X-Refresh-Token": "required"})
async def post(self) -> None:
self.write({"token": "new_jwt_token", "expires": "3600"})
. Logout¶
class LogoutHandler(SecurityHandler):
@guard_deco.require_auth(type="bearer")
@guard_deco.require_headers({"X-CSRF-Token": "required"})
async def post(self) -> None:
self.write({"status": "logged out"})
API Gateway Pattern¶
Different authentication for different API tiers:
. Public API¶
class PublicStatusHandler(SecurityHandler):
@guard_deco.api_key_auth(header_name="X-Public-Key")
async def get(self) -> None:
self.write({"status": "public api active"})
. Partner API¶
class PartnerDataHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.api_key_auth(header_name="X-Partner-Key")
@guard_deco.require_headers({"X-Partner-ID": "required"})
async def get(self) -> None:
self.write({"data": "partner exclusive"})
. Internal API¶
class InternalAdminHandler(SecurityHandler):
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
@guard_deco.api_key_auth(header_name="X-Internal-Key")
@guard_deco.require_headers(
{
"X-Service-Name": "required",
"X-Request-Context": "required",
}
)
async def get(self) -> None:
self.write({"data": "internal admin access"})
Error Handling¶
Authentication decorators return specific HTTP status codes:
- 400 Bad Request: Missing required headers
- 401 Unauthorized: Invalid or missing authentication
- 403 Forbidden: Valid auth but insufficient permissions
- 301/302 Redirect: HTTP to HTTPS redirect
. Custom Error Responses¶
config = SecurityConfig(
custom_error_responses={
400: "Missing required authentication headers",
401: "Invalid authentication credentials",
403: "Insufficient privileges for this operation",
}
)
Best Practices¶
. Layer Authentication Methods¶
Use multiple authentication factors for sensitive operations:
# Good: Multiple authentication layers
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
@guard_deco.api_key_auth(header_name="X-API-Key")
# Avoid: Single authentication method for sensitive data
# @guard_deco.api_key_auth(header_name="X-API-Key") # Too weak for sensitive ops
. Always Use HTTPS for Authentication¶
Never transmit credentials over unencrypted connections:
# Good: HTTPS enforced for login
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
# Bad: Authentication without HTTPS
# @guard_deco.require_auth(type="bearer") # Credentials could be intercepted
. Validate Header Content¶
Don't just check for presence, validate the content:
# The middleware handles presence validation
@guard_deco.require_headers({"X-API-Key": "required"})
# Your handler should validate the actual key value
class ValidatedAPIKeyHandler(SecurityHandler):
@guard_deco.require_headers({"X-API-Key": "required"})
async def get(self) -> None:
api_key = self.request.headers.get("X-API-Key")
if api_key not in VALID_KEYS:
self.set_status(401)
self.write({"error": "invalid key"})
return
self.write({"data": "ok"})
. Use Appropriate Authentication for Each Endpoint¶
Match authentication strength to data sensitivity:
# Public data: Light authentication
@guard_deco.api_key_auth(header_name="X-Public-Key")
# User data: Medium authentication
@guard_deco.require_auth(type="bearer")
# Admin data: Heavy authentication
@guard_deco.require_https()
@guard_deco.require_auth(type="bearer")
@guard_deco.api_key_auth(header_name="X-Admin-Key")
Testing Authentication¶
Test your authentication decorators with Tornado's AsyncHTTPTestCase:
from tornado.testing import AsyncHTTPTestCase
class AuthTests(AsyncHTTPTestCase):
def get_app(self):
return build_application()
def test_api_key_required(self):
response = self.fetch("/api/key-protected")
self.assertEqual(response.code, 400)
response = self.fetch(
"/api/key-protected",
headers={"X-API-Key": "valid-key"},
)
self.assertEqual(response.code, 200)
Next Steps¶
Now that you understand authentication decorators, explore other security features:
- Access Control Decorators - IP and geographic restrictions
- Rate Limiting Decorators - Request rate controls
- Behavioral Analysis - Monitor authentication patterns
- Content Filtering - Request validation
For complete API reference, see the Authentication API Documentation.