( Security )

Security defaults for Python APIs

austial.security bundles the baseline defences a backend needs before it ships. Each primitive is a small injectable class, and the module is global so any feature module can use what it needs.

What is included

  • Hardened response headers: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, X-Frame-Options and Permissions-Policy.
  • Per-route rate limiting with a guard and an @RateLimit decorator.
  • Idempotency-key replay, so a retried POST, PUT, PATCH or DELETE does not run twice.
  • Double-submit-cookie CSRF protection.
  • Structured PII redaction for logs.
  • Application-level column encryption with versioned keys.

Rate limiting a login route

The limiter is keyed on client IP, method and path. X-Forwarded-For is ignored unless you declare how many trusted proxies sit in front of the app, because the header is client-controlled. For several workers, supply a shared store such as Redis.

from austial import Controller, Post, UseGuards
from austial.security import RateLimit, RateLimitGuard


@Controller("/auth")
@UseGuards(RateLimitGuard)
class AuthController:
    @Post("/login")
    @RateLimit(5, 60)  # 5 attempts per minute
    async def login(self, body: LoginRequest) -> LoginResponse:
        ...

An audit trail to match

austial.audit adds an append-only audit log persisted through the ORM, an injectable service, and an @Audited interceptor that records who did what on a handler. Retention and legal hold are covered in the docs.

Frequently asked questions

Does Austial follow OWASP guidance?

The docs map each primitive to the OWASP ASVS and OWASP API Security Top 10 items it addresses. Treat that as a starting point for your own review, not a certification.

Is the default rate limiter production-ready for multiple workers?

The default store is in-memory and process-local. For multi-worker deployments the docs say to supply a shared store, such as a Redis-backed one.

What does the idempotency support do?

A retried POST, PUT, PATCH or DELETE that carries the same Idempotency-Key header replays the earlier response instead of executing the mutation twice.

Go deeper in the docs

( Keep reading )

( Click. Copy. Build. )

Seeing “command not found”? Run uv tool update-shell, then open a new terminal. Details