Guards¶
Use Litestar guards directly in guards=[...] route declarations. For the runtime
contract and API reference, see Guards API.
Superuser guard¶
is_superuser requires an authenticated active user and then checks normalized
role membership. By default, the user must expose the "superuser" role in
roles; set LitestarAuthConfig.superuser_role_name when your deployment uses
another normalized role name such as "admin".
Typed role guards¶
has_any_role() and has_all_roles() accept plain strings, but their Python 3.12
generic signatures also preserve narrower string subtypes. That means you can keep
role names IDE-discoverable and type-checkable instead of scattering ad-hoc string
literals through your codebase.
Plain strings¶
Plain strings remain valid and keep the existing runtime behavior:
from litestar import get
from litestar_auth.guards import has_any_role
@get("/reports", guards=[has_any_role("admin", "billing")])
async def reports_dashboard() -> dict[str, bool]:
return {"ok": True}
Literal role aliases¶
Use Literal[...] when your project has a small fixed role vocabulary and you want
type checkers to catch misspellings at call sites:
from typing import Literal
from litestar_auth.guards import has_any_role
type AppRole = Literal["admin", "billing", "support"]
ADMIN: AppRole = "admin"
BILLING: AppRole = "billing"
reports_guard = has_any_role(ADMIN, BILLING)
StrEnum role registries¶
Use StrEnum when you want a central registry that still behaves like strings at
runtime:
from enum import StrEnum
from litestar_auth.guards import has_all_roles
class AppRole(StrEnum):
ADMIN = "admin"
BILLING = "billing"
SUPPORT = "support"
finance_guard = has_all_roles(AppRole.ADMIN, AppRole.BILLING)
Normalization and rejection rules¶
Role guards normalize configured role names with trim, lowercase, deduplicate, and sort semantics before matching against the authenticated user's normalized flat role membership.
Internally, has_any_role() and has_all_roles() compare normalized role strings
with fixed-work loops rather than set-intersection or subset short-circuit
predicates. This preserves the same flat-role behavior while documenting the
library's defense-in-depth posture; it is not a cryptographic constant-time
guarantee for the full Python runtime or request path.
Invalid guard definitions fail fast during application setup instead of waiting for the first request:
- At least one role is required.
- Empty or whitespace-only role names are rejected with
ValueError.
That means has_any_role(" Admin ", "admin") collapses to one normalized
requirement, while has_any_role(" ") is rejected immediately.