Configuration¶
The plugin is driven by LitestarAuthConfig (import from litestar_auth or litestar_auth.plugin). This page lists all fields grouped by concern. Generated detail lives in the Plugin API (mkdocstrings).
ORM models and the SQLAlchemy adapter are imported from their own modules — the root package does not re-export them:
from litestar_auth import DatabaseTokenAuthConfig, LitestarAuth, LitestarAuthConfig
from litestar_auth.models import User # or your own model
from litestar_auth.db.sqlalchemy import SQLAlchemyUserDatabase
Canonical opaque DB-token preset¶
Use DatabaseTokenAuthConfig plus LitestarAuthConfig.with_database_token_auth() for the common bearer + database-token flow. This is the documented entrypoint for opaque DB tokens; it builds the AuthenticationBackend, BearerTransport, and DatabaseTokenStrategy for you.
from uuid import UUID
from litestar import Litestar
from litestar_auth import DatabaseTokenAuthConfig, LitestarAuth, LitestarAuthConfig
from litestar_auth.models import User
config = LitestarAuthConfig[User, UUID].with_database_token_auth(
database_token_auth=DatabaseTokenAuthConfig(
token_hash_secret="replace-with-32+-char-db-token-secret",
),
user_model=User,
user_manager_class=UserManager,
session_maker=session_maker,
user_manager_kwargs={
"verification_token_secret": "replace-with-32+-char-secret",
"reset_password_token_secret": "replace-with-32+-char-secret",
},
)
app = Litestar(plugins=[LitestarAuth(config)])
Here, session_maker means a callable session factory the plugin can invoke as session_maker() to obtain the request-local AsyncSession. async_sessionmaker(...) is the most common implementation, but any factory with that runtime contract is supported.
If you previously hand-assembled AuthenticationBackend(..., transport=BearerTransport(), strategy=DatabaseTokenStrategy(...)), migrate that setup to the preset above. Keep manual backends= assembly only when you need multiple backends, custom token models, or another non-canonical transport/strategy mix.
Custom SQLAlchemy User and token models¶
LitestarAuthConfig.user_model must satisfy UserProtocol (see Types): at minimum the fields and behaviors your chosen BaseUserManager and strategies use (id, email, hashed_password, is_active, is_verified, is_superuser, totp_secret as applicable).
Treat the ORM setup as three explicit layers instead of one implicit reference-model recipe:
from litestar_auth.models import import_token_orm_modelsis the canonical mapper-registration helper for the bundledAccessToken/RefreshTokentables.UserModelMixin,UserAuthRelationshipMixin,AccessTokenMixin,RefreshTokenMixin, andOAuthAccountMixinare the canonical customization path when your application owns the mapped classes.DatabaseTokenModels(...)is the strategy-side bridge only whenDatabaseTokenStrategyshould persist to custom token tables instead of the bundled defaults.
Migration note:
# Canonical mapper-registration import
from litestar_auth.models import import_token_orm_models
# Compatibility-only legacy import for existing call sites
from litestar_auth.authentication.strategy import (
import_token_orm_models as import_token_orm_models_compat,
)
Database-backed JWT / refresh (DatabaseTokenStrategy): the canonical explicit mapper-registration entrypoint for the library token models now lives under litestar_auth.models:
from litestar_auth.models import import_token_orm_models
AccessToken, RefreshToken = import_token_orm_models()
Call that helper yourself during metadata registration or Alembic-style autogenerate setup so token model discovery stays with the models boundary. Neither the plugin nor DatabaseTokenStrategy auto-registers the bundled token mappers for you. The older from litestar_auth.authentication.strategy import import_token_orm_models path remains supported only as a compatibility import while existing code migrates. If you use the library AccessToken and RefreshToken models, your user class should declare relationships compatible with them instead of copying mapper wiring from the reference User class:
- Table names:
access_token,refresh_token;user_idforeign keys targetuser.id(your user model’s table must be nameduser, or you must align FKs and relationships with your schema). - Compose the side-effect-free model mixins from
litestar_auth.modelswhen you want the bundled field and relationship contract without copying boilerplate from the reference ORM classes:
from advanced_alchemy.base import UUIDBase
from litestar_auth.models import UserAuthRelationshipMixin, UserModelMixin
class User(UserModelMixin, UserAuthRelationshipMixin, UUIDBase):
__tablename__ = "user"
UserModelMixin provides the bundled email / password / account-state columns, while UserAuthRelationshipMixin provides the access_tokens, refresh_tokens, and oauth_accounts relationships with the same back_populates="user" wiring the bundled models expect. Leave its relationship-option hooks unset to keep the default contract: SQLAlchemy's normal loader behavior plus inferred foreign-key linkage for oauth_accounts. Set any auth_*_model hook to None when a custom user only composes part of the auth model family instead of all three relationships.
If you need custom token or OAuth classes instead of the bundled AccessToken, RefreshToken, and OAuthAccount, compose their sibling mixins on your application's own declarative base / registry and override the class-name / table-name hooks instead of copying relationship code:
from advanced_alchemy.base import UUIDPrimaryKey, create_registry
from sqlalchemy.orm import DeclarativeBase
from litestar_auth.models import (
AccessTokenMixin,
OAuthAccountMixin,
RefreshTokenMixin,
UserAuthRelationshipMixin,
UserModelMixin,
)
class AppBase(DeclarativeBase):
registry = create_registry()
metadata = registry.metadata
__abstract__ = True
class AppUUIDBase(UUIDPrimaryKey, AppBase):
__abstract__ = True
class MyUser(UserModelMixin, UserAuthRelationshipMixin, AppUUIDBase):
__tablename__ = "my_user"
auth_access_token_model = "MyAccessToken"
auth_refresh_token_model = "MyRefreshToken"
auth_oauth_account_model = "MyOAuthAccount"
auth_token_relationship_lazy = "noload"
auth_oauth_account_relationship_lazy = "selectin"
auth_oauth_account_relationship_foreign_keys = "MyOAuthAccount.user_id"
class MyAccessToken(AccessTokenMixin, AppBase):
__tablename__ = "my_access_token"
auth_user_model = "MyUser"
auth_user_table = "my_user"
class MyRefreshToken(RefreshTokenMixin, AppBase):
__tablename__ = "my_refresh_token"
auth_user_model = "MyUser"
auth_user_table = "my_user"
class MyOAuthAccount(OAuthAccountMixin, AppUUIDBase):
__tablename__ = "my_oauth_account"
auth_user_model = "MyUser"
auth_user_table = "my_user"
auth_token_relationship_lazy applies the same lazy= option to both token collections, while auth_oauth_account_relationship_lazy and auth_oauth_account_relationship_foreign_keys only affect oauth_accounts. Those hooks are intentionally narrow: use them for the documented loader-strategy or explicit-foreign-key cases, and keep app-owned relationship definitions only when you truly need behavior beyond that contract.
When those custom token classes back DatabaseTokenStrategy, pass them explicitly via DatabaseTokenModels so the strategy binds repositories, refresh rotation, logout cleanup, and expired-token cleanup to your tables instead of the bundled defaults. Model registration still starts in litestar_auth.models; DatabaseTokenModels only tells the strategy which mapped token classes to use at runtime:
from litestar_auth.authentication import AuthenticationBackend
from litestar_auth.authentication.strategy import DatabaseTokenModels, DatabaseTokenStrategy
from litestar_auth.authentication.transport import BearerTransport
token_models = DatabaseTokenModels(
access_token_model=MyAccessToken,
refresh_token_model=MyRefreshToken,
)
backend = AuthenticationBackend(
name="database",
transport=BearerTransport(),
strategy=DatabaseTokenStrategy(
session=session,
token_hash_secret="replace-with-32+-char-db-token-secret",
token_models=token_models,
),
)
DatabaseTokenAuthConfig / LitestarAuthConfig.with_database_token_auth() remains the canonical shortcut for the bundled AccessToken / RefreshToken tables. Use the manual backend assembly above only when you intentionally replace the token ORM classes or need another non-canonical transport/strategy combination.
OAuth persistence: SQLAlchemyUserDatabase requires user_model and accepts optional oauth_account_model. If you use OAuth methods (get_by_oauth_account, upsert_oauth_account) without providing oauth_account_model, a TypeError is raised. A custom OAuth class can be composed from OAuthAccountMixin so the bundled column set, uniqueness rule, and user relationship stay aligned without inheriting the reference OAuthAccount class directly. Pair it with UserAuthRelationshipMixin on the user side, point auth_oauth_account_model at the custom class, and set the unused token hooks to None when you are not also composing custom token models. If that custom user also needs a non-default loader strategy for oauth_accounts, set auth_oauth_account_relationship_lazy and, only when SQLAlchemy needs an explicit hint, auth_oauth_account_relationship_foreign_keys. If your app still reuses the bundled oauth_account table on user.id, importing OAuthAccount from litestar_auth.models.oauth remains supported; otherwise prefer a mixin-based custom OAuth model whose auth_user_model / auth_user_table settings match your schema. See Custom user + OAuth.
Required (at runtime)¶
| Field | Role |
|---|---|
backends |
Non-empty sequence of AuthenticationBackend when calling LitestarAuthConfig(...) directly. The canonical DB bearer preset builds this automatically via with_database_token_auth(). |
user_model |
User ORM type (e.g. subclass of litestar_auth.models.User). |
user_manager_class |
Concrete subclass of BaseUserManager. |
session_maker |
Callable request-session factory for scoped DB access (session_maker() -> AsyncSession). async_sessionmaker(...) is the common implementation. |
On the LitestarAuthConfig dataclass, session_maker is typed as optional for advanced construction flows, but LitestarAuth raises if it is missing when the plugin is instantiated. Treat a compatible session factory as required for normal apps.
Core wiring¶
| Field | Default | Role |
|---|---|---|
user_db_factory |
None → built from user_model |
Callable[[AsyncSession], BaseUserStore]. When None, the plugin builds a default factory using config.user_model. Override for custom persistence. |
user_manager_kwargs |
{} |
Passed to user_manager_class (e.g. password_helper, token secrets). |
password_validator_factory |
None |
Build custom password policy; else default length validator when manager accepts it. |
user_manager_factory |
None |
Full control over request-scoped manager construction (UserManagerFactory). |
rate_limit_config |
None |
AuthRateLimitConfig for auth endpoint throttling. For the common shared-backend recipe, build it with AuthRateLimitConfig.from_shared_backend(). |
Paths and HTTP feature flags¶
| Field | Default | Meaning |
|---|---|---|
auth_path |
"/auth" |
Base path for generated auth controllers. |
users_path |
"/users" |
Base path for user CRUD when enabled. |
include_register |
True |
POST .../register |
include_verify |
True |
Verify + request-verify-token |
include_reset_password |
True |
Forgot + reset password |
include_users |
False |
User management routes |
enable_refresh |
False |
POST .../refresh |
requires_verification |
False |
Stricter login / TOTP-verify policy |
hard_delete |
False |
Physical vs soft delete semantics for user delete |
login_identifier |
"email" |
"email" or "username" for POST {auth_path}/login credential lookup |
Multiple backends: first backend → {auth_path}; others → {auth_path}/{backend-name}/....
Built-in auth payload boundary¶
The generated controllers do not use one universal credential field. login_identifier only changes how LoginCredentials.identifier is interpreted on POST {auth_path}/login.
| Route | Built-in request schema | Published fields |
|---|---|---|
POST {auth_path}/login |
LoginCredentials |
identifier, password |
POST {auth_path}/register |
UserCreate |
email, password |
POST {auth_path}/request-verify-token |
RequestVerifyToken |
email |
POST {auth_path}/verify |
VerifyToken |
token |
POST {auth_path}/forgot-password |
ForgotPassword |
email |
POST {auth_path}/reset-password |
ResetPassword |
token, password |
By default, built-in TOTP routes publish TotpEnableRequest, TotpConfirmEnableRequest, TotpVerifyRequest, and TotpDisableRequest. The built-in TOTP flow still uses user.email for the otpauth URI and password step-up, even when login_identifier="username".
Canonical shared-backend rate limiting¶
For the usual Redis deployment, pass one shared backend to AuthRateLimitConfig.from_shared_backend() and let the library fill in the standard auth endpoint slots:
from litestar_auth.ratelimit import AuthRateLimitConfig, RedisRateLimiter
rate_limit_config = AuthRateLimitConfig.from_shared_backend(
RedisRateLimiter(redis=redis_client, max_attempts=5, window_seconds=60),
)
from_shared_backend() exposes typed public builder identifiers from litestar_auth.ratelimit:
AuthRateLimitEndpointSlotnames the per-endpoint keys accepted byenabled,disabled,scope_overrides,namespace_overrides, andendpoint_overrides.AuthRateLimitEndpointGroupnames the shared-backend keys accepted bygroup_backends.
The private catalog that stores these defaults remains internal, but the values below are the supported builder surface:
AuthRateLimitEndpointSlot value |
AuthRateLimitEndpointGroup value |
Default scope | Default namespace token |
|---|---|---|---|
login |
login |
ip_email |
login |
refresh |
refresh |
ip |
refresh |
register |
register |
ip |
register |
forgot_password |
password_reset |
ip_email |
forgot-password |
reset_password |
password_reset |
ip |
reset-password |
totp_enable |
totp |
ip |
totp-enable |
totp_confirm_enable |
totp |
ip |
totp-confirm-enable |
totp_verify |
totp |
ip |
totp-verify |
totp_disable |
totp |
ip |
totp-disable |
verify_token |
verification |
ip |
verify-token |
request_verify_token |
verification |
ip_email |
request-verify-token |
Accepted AuthRateLimitEndpointGroup values are exactly login, refresh, register, password_reset, totp, and verification.
Builder precedence is:
endpoint_overrideswins per slot and can replace the limiter or set it toNone.- Otherwise, only slots enabled by
enabled(defaults to every supported slot) and not listed indisabledare materialized. - Generated limiters start from
backend, thengroup_backendscan swap the backend for the slot's group. scope_overridesandnamespace_overridesadjust the generated limiter for that slot.
If you already depend on custom key names or scope choices, preserve them with namespace_overrides and scope_overrides. Use disabled to leave unused slots such as verify_token or request_verify_token unset. Keep direct EndpointRateLimit(...) assembly only for advanced per-endpoint exceptions.
Migration example for an older Redis recipe: this keeps login, register, and password-reset style routes on one backend, splits out refresh and TOTP budgets, preserves legacy underscore namespaces, and leaves verification slots unset. It uses only the current shared-builder arguments; it is not a separate preset.
from litestar_auth.ratelimit import AuthRateLimitConfig, RedisRateLimiter
credential_backend = RedisRateLimiter(redis=redis_client, max_attempts=5, window_seconds=60)
refresh_backend = RedisRateLimiter(redis=redis_client, max_attempts=10, window_seconds=300)
totp_backend = RedisRateLimiter(redis=redis_client, max_attempts=5, window_seconds=300)
rate_limit_config = AuthRateLimitConfig.from_shared_backend(
credential_backend,
group_backends={"refresh": refresh_backend, "totp": totp_backend},
disabled={"verify_token", "request_verify_token"},
namespace_overrides={
"forgot_password": "forgot_password",
"reset_password": "reset_password",
"totp_enable": "totp_enable",
"totp_confirm_enable": "totp_confirm_enable",
"totp_verify": "totp_verify",
"totp_disable": "totp_disable",
},
)
Add scope_overrides only when an existing key shape also depends on a non-default scope for a specific slot.
TOTP — totp_config: TotpConfig | None¶
| Field | Default | Meaning |
|---|---|---|
totp_pending_secret |
(required) | Secret for pending-2FA JWTs; must align with auth controller. |
totp_backend_name |
None |
Which named AuthenticationBackend issues tokens after 2FA. |
totp_issuer |
"litestar-auth" |
Issuer in otpauth URI. |
totp_algorithm |
"SHA256" |
TOTP hash algorithm. |
totp_used_tokens_store |
None |
Replay store for consumed TOTP codes (required outside tests when replay protection is on). |
totp_require_replay_protection |
True |
Fail startup without a store when not in testing mode. |
totp_enable_requires_password |
True |
Step-up password for /2fa/enable. |
Routes: {auth_path}/2fa/.... See TOTP guide.
Pending-token JTI store
create_totp_controller(..., pending_jti_store=...) supports a shared JWT JTI denylist for pending login tokens. The plugin’s internal build_totp_controller does not pass this parameter; advanced deployments can mount a custom controller if they need a Redis-backed pending JTI store across workers.
OAuth — oauth_config: OAuthConfig | None¶
| Field | Default | Meaning |
|---|---|---|
oauth_cookie_secure |
True |
Secure flag for OAuth cookies. |
oauth_providers |
None |
Declared login-provider inventory for explicit login-controller registration. The canonical helper mounts GET {auth_path}/oauth/{provider}/authorize and GET {auth_path}/oauth/{provider}/callback when you pass auth_path=config.auth_path; the plugin does not auto-mount those routes from this field. |
oauth_associate_by_email |
False |
Login-controller policy for explicit OAuth login helpers. Only meaningful when oauth_providers is declared and you mount login controllers explicitly. It does not affect plugin-owned associate routes. |
include_oauth_associate |
False |
Enable plugin-owned associate flow routes. |
oauth_associate_providers |
None |
Providers auto-mounted by the plugin under GET {auth_path}/associate/{provider}/authorize and GET {auth_path}/associate/{provider}/callback when include_oauth_associate=True. |
oauth_associate_redirect_base_url |
"" |
Public redirect base for plugin-owned associate callbacks. Invalid unless the plugin owns associate routes. |
oauth_token_encryption_key |
None |
Required for any declared provider inventory in production — encrypts OAuth tokens at rest. |
Explicit login controllers may take trust_provider_email_verified (see OAuth guide).
Route-registration contract:
oauth_providersdeclares login-provider inventory only; mount login controllers explicitly withlitestar_auth.oauth.create_provider_oauth_controller(..., auth_path=config.auth_path).include_oauth_associate=Trueplus non-emptyoauth_associate_providersis the plugin-owned OAuth auto-mount path for{auth_path}/associate/{provider}/....- Ambiguous associate-only no-op configs now fail during plugin construction instead of silently producing no routes.
Security and token policy¶
| Field | Default | Meaning |
|---|---|---|
csrf_secret |
None |
Enables Litestar CSRF config when cookie transports are used. |
csrf_header_name |
"X-CSRF-Token" |
Header Litestar expects for CSRF token. |
allow_legacy_plaintext_tokens |
False |
Migration only — accept legacy plaintext DB tokens for manual DatabaseTokenStrategy setups. The canonical preset derives this from DatabaseTokenAuthConfig.accept_legacy_plaintext_tokens. |
allow_nondurable_jwt_revocation |
False |
Opt-in to in-memory JWT denylist semantics. |
id_parser |
None |
Parse path/query user ids (e.g. UUID). |
Schemas and DI¶
| Field | Default | Meaning |
|---|---|---|
user_read_schema |
None |
msgspec struct for safe user responses returned by register/verify/reset/users flows. |
user_create_schema |
None |
msgspec struct for registration/create request bodies; built-in registration defaults to UserCreate. |
user_update_schema |
None |
msgspec struct for user PATCH bodies. |
db_session_dependency_key |
"db_session" |
Litestar DI key for AsyncSession. |
db_session_dependency_provided_externally |
False |
Skip plugin session provider when your app already registers the key. |
user_*_schema customizes registration and user CRUD surfaces. It does not rename the built-in auth lifecycle request structs: LoginCredentials, RefreshTokenRequest, RequestVerifyToken, VerifyToken, ForgotPassword, ResetPassword, or the TOTP payloads.
When app-owned user_create_schema or user_update_schema structs keep a password field, import UserPasswordField from litestar_auth.schemas instead of copying raw 12 / 128 limits into local msgspec.Meta(...) annotations:
import msgspec
from litestar_auth.schemas import UserPasswordField
class AppUserCreate(msgspec.Struct):
email: str
password: UserPasswordField
display_name: str
class AppUserUpdate(msgspec.Struct, omit_defaults=True):
password: UserPasswordField | None = None
That alias keeps schema metadata aligned with the built-in UserCreate and UserUpdate structs. Runtime validation still flows through require_password_length when the plugin uses its default password_validator_factory, so schema metadata does not replace the manager-side password validator.
Dependency keys (constants)¶
Used by the plugin internally; override only if you integrate custom controllers:
litestar_auth_config,litestar_auth_user_manager,litestar_auth_backends,litestar_auth_user_model(seelitestar_auth._plugin.config).
Shared helpers — litestar_auth.config¶
validate_secret_length, is_testing, MINIMUM_SECRET_LENGTH, etc., keep token and testing behavior consistent.
Related¶
- HTTP API — routes controlled by the flags above.
- Security — production interpretation of sensitive flags.
- Plugin API — mkdocstrings for
LitestarAuth, configs, andlitestar_auth.config.