/litestar-security
Auto-activate for litestar_security, SecurityPlugin, SecurityConfig, CurrentUser, Principal, SecurityContext, requires_role, requires_scope, requires_authenticated, requires_tenant, or requires_capability. Not for raw auth guards alone — use litestar-auth-guards.
$ npx -y skills add litestar-org/litestar-skills --skill litestar-security --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/litestar-security
Context preview
The summary Claude sees to decide when to auto-load this skill.
Auto-activate for litestar_security, SecurityPlugin, SecurityConfig, CurrentUser, Principal, SecurityContext, requires_role, requires_scope, requires_authenticated, requires_tenant, or requires_capability. Not for raw auth guards alone — use litestar-auth-guards.
SKILL.md
litestar-security.SKILL.mdname: litestar-security
description: "Auto-activate for litestar_security, SecurityPlugin, SecurityConfig, CurrentUser, Principal, SecurityContext, requires_role, requires_scope, requires_authenticated, requires_tenant, or requires_capability. Not for raw auth guards alone — use litestar-auth-guards."
Litestar Security
`litestar-security` 0.3.0 is a declarative authentication and authorization framework for Litestar. It provides credential slots and mechanisms, unified session management, local accounts, MFA, WebAuthn passkeys, OAuth/OIDC, API keys, workload JWTs, and browser hardening.
Two separate axes, wired through two separate Litestar keywords:
- **Authentication** — *who is calling* — is a policy on `auth=` (or `opt={"auth": ...}`).
- **Authorization** — *what they may do* — is a predicate in Litestar's native `guards=[...]`.
Do not conflate them: the policy helpers (`public`, `required`, `any_of`, `all_of`, `at_least`) take **mechanism names**, while the guard combinators (`guard_any_of`, `guard_all_of`, `guard_at_least`, `guard_one_of`) take **predicates**.
Code Style Rules
- **Declare authentication with `auth=`.** Put policy on the route, or on a router/controller/app through `opt={"auth": ...}`. The nearest native owner wins.
- **Keep authorization in `guards=[...]`.** Litestar's `security=` parameter is reserved for the OpenAPI requirements projected from `auth`.
- **Inject the user with `CurrentUser[T]`.** Use `NamedDependency[CurrentUser[UserType]]`; it rejects anonymous and userless service principals. `principal` and `security_context` stay typed on public routes too.
- **Authorize from the snapshot.** Guards read the `AuthorizationSnapshot` produced by the configured `authorization_resolver`. Never query the database inside a guard.
- **Exclude other plugins' routes by path.** Static assets and dashboards carry no `auth` and compile to implicit `required()`, so they answer `401` until listed in `SecurityConfig(exclude=[...])`.
- **Secure WebSockets with connect tokens.** Browsers cannot set handshake headers; mint a short-lived token over authenticated HTTP.
- **Load protector keys from a secret store.** MFA and OAuth protectors need application-owned 32-byte AES-256-GCM keys, never source literals.
Quick Reference
Plugin Registration
from litestar import Litestar, get
from litestar.di import NamedDependency
from litestar_security import (
SecurityConfig,
SecurityContext,
SecurityPlugin,
public,
)
@get("/", auth=public(), sync_to_thread=False)
def index(security_context: NamedDependency[SecurityContext]) -> dict[str, bool]:
return {"authenticated": bool(security_context.evidence)}
app = Litestar(
route_handlers=[index],
plugins=[SecurityPlugin(SecurityConfig())],
)With mechanisms configured and no inherited policy, routes default to implicit `required()`. With no mechanisms at all they are public.
Authentication Policy
from litestar import Controller, get
from litestar_security import all_of, any_of, at_least, public, required
required() # any configured mechanism
required("session") # one named mechanism
any_of("session", "api_key") # either
all_of("api_key", "workload_jwt") # both, same subject
at_least(2, "session", "api_key", "passkey") # N of M
public() # no authentication, excluded from native CSRFApply it at whichever layer owns the decision:
@get("/health", auth=public())
async def health() -> dict[str, str]:
return {"status": "ok"}
class AccountController(Controller):
opt = {"auth": required("session")}Custom controller class attributes are not propagated by Litestar — policy must live in `opt`, or use the typed `SecureController` / `PublicController` base classes.
Authorization Guards
from litestar import Controller, get
from litestar_security import guard_any_of, requires_role, requires_scope
class ReportsController(Controller):
path = "/reports"
opt = {"auth": required("session")}
guards = [requires_role("analyst")]
@get("/", guards=[guard_any_of(requires_scope("read:all"), requires_scope("read:reports"))])
async def list_reports(self) -> list[dict[str, str]]: ...Reserved Dependency Names
The plugin registers these; do not shadow them.
| Key | Type | Use | | --- | --- | --- | | `principal` | `Principal` | Stable envelope identity plus the active user model | | `security_context` | `SecurityContext` | Active session, evidence, snapshot, and restrictions | | `current_user` | `CurrentUser[User]` | Narrowing shortcut; rejects anonymous and service principals | | `websocket_connect_tokens` | `WebSocketConnectTokenService` | WebSocket connect-token manager |
Status Code Contract
| Outcome | Status | | --- | --- | | Authentication failure | `401` | | Guard denial | `403` | | Verification unavailable (fails closed) | `503` |
<workflow>
Workflow
Step 1: Install the capabilities in use
Core install covers JWT/JWKS validation, API keys, IAP, and OIDC token verification. Add an extra only for what the application uses: `[mfa]`, `[passkeys]`, `[oauth]`, `[argon2]`, or `[all]`.
Step 2: Choose providers
Pick where identity is established — local accounts, OAuth/OIDC, Google IAP, API keys, or workload JWTs. Adding a provider makes its mechanism available; route policy decides where it is accepted. See [Providers](references/providers.md).
Step 3: Implement the authorization resolver
Write a callable taking the authenticated `Principal` and returning an `AuthorizationSnapshot` of granted roles, scopes, capabilities, teams, and tenants. It runs once per request, which is why guards must not perform I/O.
from litestar_security import AuthorizationSnapshot, Principal
async def resolve_user_authorization(principal: Principal[User]) -> AuthorizationSnapshot:
if not principal.is_authenticated:
return AuthorizationSnapshot()
user = principal.Read more
name: litestar-security description: "Auto-activate for litestar_security, SecurityPlugin, SecurityConfig, CurrentUser, Principal, SecurityContext, requires_role, requires_scope, requires_authenticated, requires_tenant, or requires_capability. Not for raw auth guards alone — use litestar-auth-guards."
Litestar Security
`litestar-security` 0.3.0 is a declarative authentication and authorization framework for Litestar. It provides credential slots and mechanisms, unified session management, local accounts, MFA, WebAuthn passkeys, OAuth/OIDC, API keys, workload JWTs, and browser hardening.
Two separate axes, wired through two separate Litestar keywords:
- **Authentication** — *who is calling* — is a policy on `auth=` (or `opt={"auth": ...}`).
- **Authorization** — *what they may do* — is a predicate in Litestar's native `guards=[...]`.
Do not conflate them: the policy helpers (`public`, `required`, `any_of`, `all_of`, `at_least`) take **mechanism names**, while the guard combinators (`guard_any_of`, `guard_all_of`, `guard_at_least`, `guard_one_of`) take **predicates**.
Code Style Rules
- **Declare authentication with `auth=`.** Put policy on the route, or on a router/controller/app through `opt={"auth": ...}`. The nearest native owner wins.
- **Keep authorization in `guards=[...]`.** Litestar's `security=` parameter is reserved for the OpenAPI requirements projected from `auth`.
- **Inject the user with `CurrentUser[T]`.** Use `NamedDependency[CurrentUser[UserType]]`; it rejects anonymous and userless service principals. `principal` and `security_context` stay typed on public routes too.
- **Authorize from the snapshot.** Guards read the `AuthorizationSnapshot` produced by the configured `authorization_resolver`. Never query the database inside a guard.
- **Exclude other plugins' routes by path.** Static assets and dashboards carry no `auth` and compile to implicit `required()`, so they answer `401` until listed in `SecurityConfig(exclude=[...])`.
- **Secure WebSockets with connect tokens.** Browsers cannot set handshake headers; mint a short-lived token over authenticated HTTP.
- **Load protector keys from a secret store.** MFA and OAuth protectors need application-owned 32-byte AES-256-GCM keys, never source literals.
Quick Reference
Plugin Registration
from litestar import Litestar, get
from litestar.di import NamedDependency
from litestar_security import (
SecurityConfig,
SecurityContext,
SecurityPlugin,
public,
)
@get("/", auth=public(), sync_to_thread=False)
def index(security_context: NamedDependency[SecurityContext]) -> dict[str, bool]:
return {"authenticated": bool(security_context.evidence)}
app = Litestar(
route_handlers=[index],
plugins=[SecurityPlugin(SecurityConfig())],
)With mechanisms configured and no inherited policy, routes default to implicit `required()`. With no mechanisms at all they are public.
Authentication Policy
from litestar import Controller, get
from litestar_security import all_of, any_of, at_least, public, required
required() # any configured mechanism
required("session") # one named mechanism
any_of("session", "api_key") # either
all_of("api_key", "workload_jwt") # both, same subject
at_least(2, "session", "api_key", "passkey") # N of M
public() # no authentication, excluded from native CSRFApply it at whichever layer owns the decision:
@get("/health", auth=public())
async def health() -> dict[str, str]:
return {"status": "ok"}
class AccountController(Controller):
opt = {"auth": required("session")}Custom controller class attributes are not propagated by Litestar — policy must live in `opt`, or use the typed `SecureController` / `PublicController` base classes.
Authorization Guards
from litestar import Controller, get
from litestar_security import guard_any_of, requires_role, requires_scope
class ReportsController(Controller):
path = "/reports"
opt = {"auth": required("session")}
guards = [requires_role("analyst")]
@get("/", guards=[guard_any_of(requires_scope("read:all"), requires_scope("read:reports"))])
async def list_reports(self) -> list[dict[str, str]]: ...Reserved Dependency Names
The plugin registers these; do not shadow them.
| Key | Type | Use | | --- | --- | --- | | `principal` | `Principal` | Stable envelope identity plus the active user model | | `security_context` | `SecurityContext` | Active session, evidence, snapshot, and restrictions | | `current_user` | `CurrentUser[User]` | Narrowing shortcut; rejects anonymous and service principals | | `websocket_connect_tokens` | `WebSocketConnectTokenService` | WebSocket connect-token manager |
Status Code Contract
| Outcome | Status | | --- | --- | | Authentication failure | `401` | | Guard denial | `403` | | Verification unavailable (fails closed) | `503` |
<workflow>
Workflow
Step 1: Install the capabilities in use
Core install covers JWT/JWKS validation, API keys, IAP, and OIDC token verification. Add an extra only for what the application uses: `[mfa]`, `[passkeys]`, `[oauth]`, `[argon2]`, or `[all]`.
Step 2: Choose providers
Pick where identity is established — local accounts, OAuth/OIDC, Google IAP, API keys, or workload JWTs. Adding a provider makes its mechanism available; route policy decides where it is accepted. See [Providers](references/providers.md).
Step 3: Implement the authorization resolver
Write a callable taking the authenticated `Principal` and returning an `AuthorizationSnapshot` of granted roles, scopes, capabilities, teams, and tenants. It runs once per request, which is why guards must not perform I/O.
from litestar_security import AuthorizationSnapshot, Principal
async def resolve_user_authorization(principal: Principal[User]) -> AuthorizationSnapshot:
if not principal.is_authenticated:
return AuthorizationSnapshot()
user = principal.Opinionated, first-party agent skills, plugins, subagents, slash commands, and MCP servers for the Litestar framework and its ecosystem — publishable to every major AI agent and IDE from a single repo.
Repo: litestar-org/litestar-skills
Other skills on litestar.
- /advanced-alchemy
Auto-activate for advanced_alchemy imports, alembic/, SQLAlchemyAsyncRepositoryService, SQLAlchemyAsyncConfig, repository_type, service_class, filters, or storage. Not for raw SQLAlchemy without Advanced Alchemy — use SQLAlchemy guidance.
Open skill - /litestar-ai-serving
Auto-activate for Google ADK, LlmAgent, Runner, SQLSpecSessionService, Vertex AI, SSE agent chats, tool calls, or Litestar model workflows. Not for offline ML training.
Open skill - /litestar-auth-guards
Auto-activate for guards=, Guard, ASGIConnection, JWTAuth, JWTCookieAuth, SessionAuth, role or tenant checks, or WebSocket auth. Not for frontend route protection.
Open skill - /litestar-autowire
Auto-activate for litestar_autowire, AutowirePlugin, AutowireConfig, domain_packages, AutowireIntegration, AutowireLoader, clear_autowire_cache, or automatic controller/listener/task discovery. Not for manual Router composition — keep explicit wiring when discovery adds no value.
Open skill - /litestar-build
Auto-activate for uv build, hatch build, PyApp, PYAPP_*, wheel assets, GitHub release matrices, cargo-zigbuild, or python-build-standalone. Not for runtime deployment.
Open skill - /litestar-data-services
Auto-activate for SQLAlchemyAsyncRepositoryService, SQLSpecAsyncService, create_filter_dependencies, LimitOffsetFilter, OffsetPagination, filters, or CRUD services. Not for raw drivers.
Open skill

