v0.4.0 Release Notes¶
Release Date: August 2025
This release focuses on security and production readiness. Cello v0.4.0 adds JWT authentication, configurable rate limiting, secure cookie sessions, automatic security headers, multi-process cluster mode, and native TLS support -- everything needed to deploy Cello behind no reverse proxy at all if desired.
Highlights¶
- JWT Authentication -- Issue, verify, and refresh JSON Web Tokens entirely in Rust
- Rate Limiting -- Token bucket and sliding window algorithms with per-route configuration
- Session Management -- Encrypted cookie sessions with automatic rotation
- Security Headers -- CSP, HSTS, X-Frame-Options, and more applied automatically
- Cluster Mode -- Multi-process workers sharing a single port
- TLS Support -- Native HTTPS via rustls without an external proxy
New Features¶
JWT Authentication¶
Full JWT support powered by the jsonwebtoken crate with constant-time token comparison via subtle.
from cello import App, JwtConfig
app = App()
app.enable_jwt(JwtConfig(
secret="your-secret-key",
algorithm="HS256",
expiry=3600, # 1 hour
issuer="cello-app",
refresh_expiry=86400, # 24 hours
))
@app.post("/login")
def login(request):
user = authenticate(request.json())
token = app.jwt.create_token({"sub": user.id, "role": user.role})
return {"access_token": token}
@app.get("/protected")
def protected(request):
claims = request.jwt_claims # Populated by JWT middleware
return {"user_id": claims["sub"]}
Supported algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384
Rate Limiting¶
Two built-in algorithms with per-route and global configuration.
from cello import App, RateLimitConfig
app = App()
# Global rate limit
app.enable_rate_limit(RateLimitConfig(
requests=100,
window=60,
strategy="sliding_window", # or "token_bucket"
))
Rate-limited responses include standard headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed |
X-RateLimit-Remaining | Requests remaining in window |
X-RateLimit-Reset | Seconds until window resets |
Retry-After | Seconds to wait (on 429 responses) |
Session Management¶
Encrypted, signed cookie sessions with no external store required.
from cello import App, SessionConfig
app = App()
app.enable_sessions(SessionConfig(
secret="session-encryption-key",
cookie_name="cello_session",
max_age=86400,
http_only=True,
secure=True,
same_site="Lax",
))
@app.get("/dashboard")
def dashboard(request):
visits = request.session.get("visits", 0) + 1
request.session["visits"] = visits
return {"visits": visits}
Security features:
- AES-256-GCM encryption for session data
- HMAC signature to detect tampering
- Automatic key rotation when
max_ageexpires SameSitecookie attribute to prevent CSRF
Security Headers¶
Apply a comprehensive set of security headers to every response.
from cello import App, SecurityHeadersConfig
app = App()
app.enable_security_headers(SecurityHeadersConfig(
hsts=True,
hsts_max_age=31536000,
hsts_include_subdomains=True,
content_type_nosniff=True,
frame_options="DENY",
xss_protection=True,
referrer_policy="strict-origin-when-cross-origin",
csp="default-src 'self'; script-src 'self'",
))
Applied headers:
Strict-Transport-Security(HSTS)X-Content-Type-Options: nosniffX-Frame-OptionsX-XSS-ProtectionReferrer-PolicyContent-Security-Policy
Cluster Mode¶
Run multiple worker processes sharing a single port using SO_REUSEPORT.
Each worker runs its own Tokio runtime with independent event loops. This sidesteps the Python GIL by using separate processes while the Rust layer handles port sharing.
TLS Support¶
Native HTTPS without needing nginx or a load balancer in front.
from cello import App, TlsConfig
app = App()
app.run(
host="0.0.0.0",
port=443,
tls=TlsConfig(
cert_path="/etc/certs/cert.pem",
key_path="/etc/certs/key.pem",
),
)
Powered by rustls 0.22 -- no OpenSSL dependency. Supports TLS 1.2 and 1.3 with modern cipher suites.
Improvements¶
Performance¶
- 10% faster routing through improved radix tree traversal
- Lower memory per connection with optimized buffer pooling
- Faster JSON responses through pre-allocated serialization buffers
Developer Experience¶
--envCLI flag for switching between development and production modes- Automatic reload in development mode (watches Python files for changes)
- Colored log output with request timing in debug mode
Breaking Changes¶
Middleware Registration Order¶
Middleware now executes in the order it is registered, rather than by internal priority. If you relied on implicit ordering, verify your middleware chain.
# v0.4.0: Middleware runs in registration order
app.enable_cors(...) # Runs first
app.enable_rate_limit(...) # Runs second
app.enable_jwt(...) # Runs third
Bug Fixes¶
- Fixed
OPTIONSpreflight not bypassing rate limiting - Fixed blueprint middleware not inheriting parent app middleware
- Fixed WebSocket upgrade failing when compression middleware was enabled
- Fixed static file MIME type detection for
.wasmand.mjsfiles - Fixed SSE connections not being cleaned up on client disconnect
Dependencies Added¶
| Dependency | Version | Purpose |
|---|---|---|
jsonwebtoken | 9.0 | JWT creation and verification |
subtle | 2.5 | Constant-time token comparison |
rustls | 0.22 | Native TLS implementation |
Migration from v0.3.0¶
No application code changes required. New features are opt-in.
-
Update your dependency:
-
Optionally enable new middleware:
-
For production, consider adding TLS and cluster mode:
Full Changelog¶
See the complete changelog for all changes in this release.