Models¶
Package litestar_auth.models exposes the reference User, Role, UserRole,
OAuthAccount, ApiKey, Organization, and OrganizationMembership ORM models
plus the side-effect-free mixins behind the bundled model family.
Names are loaded lazily (PEP 562) when accessed on the package.
Import paths¶
| Goal | Import |
|---|---|
| Shared auth-model mixins without registering reference mappers | from litestar_auth.models.mixins import UserModelMixin, UserAuthRelationshipMixin, UserRoleRelationshipMixin, RoleMixin, UserRoleAssociationMixin, OrganizationMixin, OrganizationMembershipMixin, OAuthAccountMixin, ApiKeyMixin, AccessTokenMixin, RefreshTokenMixin |
Bundled AccessToken / RefreshToken / RefreshTokenConsumedDigest mapper bootstrap |
from litestar_auth.models import import_token_orm_models |
Bundled role tables without loading reference User |
from litestar_auth.models.role import Role, UserRole |
| Bundled organization tables without loading root package models | from litestar_auth.models.organization import Organization, OrganizationMembership |
API-key table contract without loading reference User |
from litestar_auth.models.api_key import ApiKey |
OAuth table contract without loading reference User |
from litestar_auth.models.oauth import OAuthAccount |
Reference User (and typical tests / quickstarts) |
from litestar_auth.models import User or from litestar_auth.models.user import User |
Use Configuration as the
main ORM setup guide for token bootstrap lifecycle, relational role composition, custom model
families, SQLAlchemyUserDatabase, and password-column customization. Use the Custom user +
OAuth cookbook when the application owns the user table.
Avoid from litestar_auth.models import User (or the user submodule) in apps that already map table user to a custom model. That import registers the bundled reference mapper and conflicts with an app-owned mapping. Likewise, importing OAuthAccount from litestar_auth.models.oauth only keeps the reference User lazy; when the app owns a different user class, table, or registry, prefer an OAuthAccountMixin subclass that points back at the custom user contract.
import_token_orm_models() remains the explicit helper for bundled token metadata bootstrap and Alembic-style autogenerate. It returns AccessToken, RefreshToken, and RefreshTokenConsumedDigest so the bundled refresh-token consumed-digest lookup table is part of the documented bootstrap surface. LitestarAuth.on_app_init() also calls the same helper lazily for plugin-managed runtime when bundled DB-token models are active, so no extra import side effect is required only to make the plugin work. DatabaseTokenModels defaults to those same three classes at runtime; pass consumed_refresh_token_digest_model=... only when a custom consumed-digest lookup table should back refresh-token replay detection.
For custom SQLAlchemy models, compose the mixins on your own declarative base instead of copying columns or relationship wiring from the reference classes. Configuration covers the full support matrix and migration notes.
refresh_token session metadata¶
The bundled RefreshTokenMixin stores refresh tokens as keyed digests only. It also adds the DB-backed
session metadata required by session/device management:
session_id— a generated UUID string used as the stable public session identifier. It is distinct fromtokenand must be the only refresh-session identifier exposed by API responses.created_at— the original refresh session creation timestamp.last_used_at— nullable timestamp set when a refresh token is successfully rotated.client_metadata— nullable bounded JSON metadata derived from login/refresh requests. The built-in controller stores only a normalizeduser_agentvalue capped at 255 characters.
Refresh rotation keeps the same session_id and created_at, atomically replaces only the token digest,
records the consumed digest, updates last_used_at, and refreshes client_metadata when request metadata
is available. Re-presenting any consumed refresh token is treated as a compromise signal and revokes the
entire refresh-session chain. The bundled strategy also stores each consumed digest in
refresh_token_consumed_digest, keyed by digest with an index on session_id, so replay checks perform an
indexed equality lookup instead of scanning refresh-token rows.
Existing deployments using the bundled refresh_token table must add session_id, last_used_at, and
client_metadata columns before using this version. Deployments upgrading to refresh-token reuse detection
must also create the refresh_token_consumed_digest lookup table. Backfill session_id with a unique
non-sensitive UUID per existing row. If the deployment is upgrading from a version that stored legacy
digests in refresh_token.consumed_token_digests, backfill every legacy digest into
refresh_token_consumed_digest, then drop the legacy JSON column before serving traffic with the new code.
Skipping the lookup-table backfill means refresh tokens consumed before the upgrade and replayed after
it are rejected as ordinary missing tokens instead of revoking the compromised session chain until the
legacy sessions expire or are explicitly revoked. Existing custom refresh-token models passed through
DatabaseTokenModels must expose mapped session_id, last_used_at, and client_metadata attributes;
custom consumed-digest models must expose mapped token_digest, session_id, and consumed_at attributes.
Otherwise configuration fails fast with ConfigurationError.
api_key shape¶
The bundled ApiKeyMixin stores API-key metadata and verifier material:
key_id— public lookup id embedded in the raw credential.hashed_secret— keyed HMAC digest of the raw bearer secret.encrypted_secret— nullable encrypted raw secret for signing-required keys.name,scopes,prefix_env,signing_required,expires_at,last_used_at,revoked_at,created_via, andclient_metadata— safe management metadata.
Import ApiKey from litestar_auth.models.api_key or lazily from litestar_auth.models. Use
ApiKeyMixin on a custom declarative base when the application owns the model family. The SQLAlchemy
store lives at litestar_auth.db.sqlalchemy.SQLAlchemyApiKeyStore; the lazy litestar_auth.db
package exports only BaseApiKeyStore and ApiKeyData.
Lazy imports and IDE support¶
litestar_auth.models exposes names such as User and OAuthAccount through PEP
562 __getattr__ so that importing the package does not
register SQLAlchemy mappers or run other ORM side effects until a symbol is accessed.
Static type checkers still see those symbols with full annotations (the package uses
TYPE_CHECKING-friendly patterns for stubs and forward references). Some IDEs cannot resolve
go to definition or offer reliable autocomplete through a runtime __getattr__ hook. For full
IDE support—jump to definition, rename, and completion—import from the concrete modules directly:
from litestar_auth.models.user import Userfrom litestar_auth.models.oauth import OAuthAccountfrom litestar_auth.models.organization import Organization, OrganizationMembership
The import paths table restates the same guidance in task-oriented form.
UserModelMixin hook¶
UserModelMixin keeps the runtime attribute contract on hashed_password. When an app-owned user table only needs a different SQL column name, set auth_hashed_password_column_name on the custom user class:
class CustomUser(UserModelMixin, UserAuthRelationshipMixin, AppUUIDBase):
__tablename__ = "custom_user"
auth_hashed_password_column_name = "password_hash"
BaseUserManager, SQLAlchemyUserDatabase, and JWT password fingerprinting still read and write user.hashed_password; only the SQL column name changes. If an app needs more than a column-name remap, it can still own the mapped attribute directly with hashed_password = mapped_column(...) on the app model.
UserAuthRelationshipMixin hooks¶
UserAuthRelationshipMixin keeps the bundled inverse relationship contract by default: back_populates="user" on access_tokens, refresh_tokens, and oauth_accounts, with SQLAlchemy's normal loader behavior and inferred foreign-key linkage. Override only the narrow class hooks the mixin documents:
auth_access_token_model,auth_refresh_token_model,auth_oauth_account_modelpoint those inverse relationships at custom mapped classes, or toNonewhen a branch is intentionally omitted.auth_token_relationship_lazyforwards one optionallazy=setting to both token collections.auth_oauth_account_relationship_lazyforwards one optionallazy=setting tooauth_accounts.auth_oauth_account_relationship_foreign_keysforwards one optionalforeign_keys=hint tooauth_accounts.
The mixin does not accept arbitrary relationship() kwargs. For behavior outside those hooks, keep an app-owned explicit relationship definition.
Relational role hooks¶
UserRoleRelationshipMixin is the supported user-side role facade. It keeps
user.roles -> list[str] as the normalized public contract while persisting membership through
relationship rows instead of a JSON column on the user table.
auth_user_role_modelpointsrole_assignmentsat the association-row mapper.auth_user_role_relationship_lazyforwards one optionallazy=setting torole_assignments.
RoleMixin and UserRoleAssociationMixin provide the sibling tables behind that facade:
RoleMixinmaps the global role catalog row (name) plus inverseuser_assignments.UserRoleAssociationMixinmaps the(user_id, role_name)association row and theuser/rolerelationships.- The association mixin hooks (
auth_user_model,auth_user_table,auth_role_model,auth_role_table) let apps point the same boilerplate at custom table names and mapped classes.
The bundled User model composes UserRoleRelationshipMixin, and the bundled Role /
UserRole models are the reference implementation of the same contract.
Role shape¶
The bundled relational role family consists of:
role.name— normalized global role name, primary keyuser_role.user_id— foreign key touser.id, part of the composite primary keyuser_role.role_name— foreign key torole.name, part of the composite primary key
At the library boundary, the user contract is still the normalized flat roles: list[str]
surface consumed by managers, schemas, and guards. The relational tables are an internal
persistence detail of the bundled/custom SQLAlchemy model family, not a change to the higher-level
role API.
Migrating from legacy JSON roles¶
If an existing deployment still stores roles in a JSON column on the user row, migrate in this order:
- Create
roleanduser_role, or the equivalent custom tables built fromRoleMixin/UserRoleAssociationMixin. - Normalize and deduplicate each stored role array with the same trim/lowercase rules used by the library.
- Backfill one
rolerow per normalized name and oneuser_rolerow per(user, role)pair. - Switch the app to the bundled
Role/UserRolemodels or a custom mixin-composed role family. - Remove or ignore the legacy JSON column once reads and writes use relational membership.
Relational role storage does not change the higher-level auth contract: managers, schemas, and
guards still operate on flat normalized roles, and the library does not provide RBAC permission
matrices or policy DSLs.
Organization shape¶
The bundled organization family consists of:
organization.id— UUID primary keyorganization.slug— normalized unique tenant slug, indexedorganization.name— display nameorganization.created_at/organization.updated_at— server-managed audit timestampsorganization_membership.user_id— foreign key touser.id, part of the composite primary keyorganization_membership.organization_id— foreign key toorganization.id, part of the composite primary keyorganization_membership.roles— normalized JSON list of organization-scoped role names- Unique constraint on
(user_id, organization_id)
Import the reference models lazily from litestar_auth.models or directly from
litestar_auth.models.organization:
OrganizationMixin and OrganizationMembershipMixin are side-effect-free composition helpers for
custom declarative bases. The membership mixin reuses the same configurable user foreign-key
contract as other user-owned auth rows and adds configurable organization-table hooks.
Organization models are intentionally not exported from litestar_auth or litestar_auth.db.
litestar_auth.db exports only BaseOrganizationStore, OrganizationData, and MembershipData;
the SQLAlchemy adapter lives at litestar_auth.db.sqlalchemy.SQLAlchemyOrganizationStore.
Phase-1 organization persistence does not alter authorization behavior. There are no
organization-scoped guards, tenant-resolution middleware, JWT org_id claim, organization admin
routes, or automatic filters for application-owned tables.
oauth_account shape¶
The library table (bundled OAuthAccount) includes at least:
id— UUID primary key (fromUUIDBase)user_id— FK touser.id, not nulloauth_name—String(100)account_id—String(255)account_email—String(320)access_token—EncryptedString-backed (length 4096), Fernet when a key is configuredexpires_at— integer epoch or nullrefresh_token— optional, same encryption type as access token- Unique constraint
uq_oauth_account_provider_identityon(oauth_name, account_id)
Token encryption uses litestar_auth.oauth_encryption and OAuthConfig.oauth_token_encryption_keyring or the one-key oauth_token_encryption_key shortcut (see OAuth guide).
For audit columns (created_at / updated_at), use one mapped class per table; see OAuth guide — audit columns.
litestar_auth.models
¶
ORM models package.
Use :func:import_token_orm_models from this package as the explicit bootstrap helper
for the bundled token tables so mapper discovery stays under the models boundary.
Import :mod:litestar_auth.models.oauth when you need
:class:~litestar_auth.models.oauth.OAuthAccount without registering the library
:class:~litestar_auth.models.user.User (for example, with a custom user table).
For custom user, token, or OAuth classes, compose the side-effect-free ORM mixins exposed here on
your own registry instead of copying fields or relationships from the reference models. When those
custom token tables back :class:~litestar_auth.authentication.strategy.DatabaseTokenStrategy,
pair them with :class:~litestar_auth.authentication.strategy.DatabaseTokenModels.
The package still supports from litestar_auth.models import User, OAuthAccount via lazy
attributes (PEP 562). Static type checkers use the TYPE_CHECKING imports below.
AccessTokenMixin
¶
Bases: _TokenModelMixin
Shared mapped attributes for access-token models.
ApiKey
¶
Bases: ApiKeyMixin, UUIDBase
API key linked to a local user.
The non-secret key_id is globally unique and indexed so future authentication
strategies can resolve candidate rows without scanning or comparing every stored
digest. hashed_secret stores the keyed secret digest; the raw secret is never
represented on the ORM model. encrypted_secret is reserved for signing-mode
storage and remains nullable until that feature is enabled by a later task.
ApiKeyMixin
¶
Bases: _UserOwnedMixin
Shared mapped attributes for API-key credential rows.
OAuthAccount
¶
Bases: OAuthAccountMixin, UUIDBase
OAuth account linked to a local user.
Provider identity (oauth_name, account_id) is globally unique: one provider identity can only be linked to one local user. Enforced at the persistence layer via UniqueConstraint and upsert logic.
The user relationship targets the declarative class named User in the
same registry (the bundled :class:~litestar_auth.models.user.User or your
replacement). The default inverse side lives in
:class:~litestar_auth.models.mixins.UserAuthRelationshipMixin.
Configure foreign_keys / overlaps on subclasses if you remap
relationships (see the custom user + OAuth cookbook).
OAuthAccountMixin
¶
Bases: _UserOwnedMixin
Shared columns and relationship wiring for OAuth account models.
access_token = mapped_column(oauth_access_token_type)
class-attribute
instance-attribute
¶
OAuth provider access token. Fernet-encrypted at rest when configured.
refresh_token = mapped_column(oauth_refresh_token_type, default=None, nullable=True)
class-attribute
instance-attribute
¶
OAuth provider refresh token. Fernet-encrypted at rest when configured.
__init_subclass__(**kwargs)
¶
Register OAuth token encryption hooks when an OAuth model family is declared.
Source code in litestar_auth/models/mixins.py
__table_args__()
classmethod
¶
Create the provider-identity uniqueness constraint for each subclass.
Returns:
| Type | Description |
|---|---|
tuple[UniqueConstraint]
|
The unique constraint tuple for |
Source code in litestar_auth/models/mixins.py
Organization
¶
OrganizationInvitation
¶
Bases: OrganizationInvitationMixin, DefaultBase
Bundled organization invitation row storing only a token digest.
OrganizationInvitationMixin
¶
Map one single-use invitation token digest for one organization.
organization()
classmethod
¶
Map the relationship back to the configured organization model.
Returns:
| Type | Description |
|---|---|
Mapped[Any]
|
The relationship descriptor for the configured organization model. |
Source code in litestar_auth/_auth_model_mixins.py
organization_id()
classmethod
¶
Map the organization foreign key for the invitation row.
Returns:
| Type | Description |
|---|---|
Mapped[UUID]
|
The mapped organization foreign-key column. |
Source code in litestar_auth/_auth_model_mixins.py
OrganizationMembership
¶
Bases: OrganizationMembershipMixin, DefaultBase
Bundled join row linking one user to one organization.
OrganizationMembershipMixin
¶
Bases: _UserOwnedMixin
Map one user's normalized role membership in one organization.
organization()
classmethod
¶
Map the relationship back to the configured organization model.
Returns:
| Type | Description |
|---|---|
Mapped[Any]
|
The relationship descriptor for the configured organization model. |
Source code in litestar_auth/_auth_model_mixins.py
organization_id()
classmethod
¶
Map the organization foreign key for the membership row.
Returns:
| Type | Description |
|---|---|
Mapped[UUID]
|
The mapped organization foreign-key column. |
Source code in litestar_auth/_auth_model_mixins.py
OrganizationMixin
¶
Shared columns and inverse relationship for organization catalog rows.
invitations()
classmethod
¶
Map the inverse collection of organization-invitation rows.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor for organization-invitation rows. |
Source code in litestar_auth/_auth_model_mixins.py
memberships()
classmethod
¶
Map the inverse collection of organization-membership rows.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor for organization-membership rows. |
Source code in litestar_auth/_auth_model_mixins.py
RefreshTokenMixin
¶
Bases: _TokenModelMixin
Shared mapped attributes for refresh-token models.
Role
¶
RoleMixin
¶
Shared columns and inverse relationship for relational roles.
user_assignments()
classmethod
¶
Map the inverse collection of user-role association rows.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor for user-role association rows. |
Source code in litestar_auth/_auth_model_mixins.py
User
¶
Bases: UserModelMixin, UserRoleRelationshipMixin, UserAuthRelationshipMixin, UUIDBase
Base user model for authentication and authorization flows.
UserAuthRelationshipMixin
¶
Declare the inverse relationships expected by the auth ORM model families.
Override the auth_*_model class variables when a custom user model needs
to point at custom token or OAuth classes instead of the bundled defaults.
Configure the supported relationship-option hooks when a custom user model
needs non-default loader strategies or an explicit OAuth foreign_keys
setting without redefining the declared_attr methods. Set a model hook
to None when the custom user only composes part of the auth model family
and should omit that inverse relationship entirely.
access_tokens()
classmethod
¶
Map the inverse side of the configured access-token model when enabled.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor, or |
Source code in litestar_auth/_auth_model_mixins.py
api_keys()
classmethod
¶
Map the inverse side of the configured API-key model when enabled.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor, or |
Source code in litestar_auth/_auth_model_mixins.py
oauth_accounts()
classmethod
¶
Map the inverse side of the configured OAuth-account model when enabled.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor, or |
Source code in litestar_auth/_auth_model_mixins.py
organization_memberships()
classmethod
¶
Map the inverse side of the configured organization-membership model when enabled.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor, or |
Source code in litestar_auth/_auth_model_mixins.py
refresh_tokens()
classmethod
¶
Map the inverse side of the configured refresh-token model when enabled.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor, or |
Source code in litestar_auth/_auth_model_mixins.py
UserModelMixin
¶
Shared non-primary-key columns used by the bundled User model.
Provides email, hashed_password, is_active, is_verified,
totp_secret, and hashed TOTP recovery codes. Superuser status is
determined by role membership, not by a persisted column on this mixin.
Set auth_hashed_password_column_name on a subclass when the app keeps
the public hashed_password attribute but stores it under a different
SQL column name such as password_hash.
hashed_password()
classmethod
¶
Map the password-hash attribute to the configured SQL column name.
Returns:
| Type | Description |
|---|---|
Mapped[str]
|
The mapped |
Source code in litestar_auth/_auth_model_mixins.py
UserRole
¶
UserRoleAssociationMixin
¶
Bases: _UserOwnedMixin
Map one normalized role assignment for one user.
role()
classmethod
¶
Map the relationship back to the configured role model.
Returns:
| Type | Description |
|---|---|
Mapped[Any]
|
The relationship descriptor for the configured role model. |
Source code in litestar_auth/_auth_model_mixins.py
role_name()
classmethod
¶
Map the normalized role-name foreign key for the association row.
Returns:
| Type | Description |
|---|---|
Mapped[str]
|
The mapped role-name foreign-key column. |
Source code in litestar_auth/_auth_model_mixins.py
UserRoleRelationshipMixin
¶
Expose normalized flat roles through relational assignment rows.
The returned roles value is a normalized snapshot. Persist changes by
assigning a new iterable to user.roles instead of mutating the returned
list in place.
roles
property
writable
¶
Return normalized flat role membership for the current user.
role_assignments()
classmethod
¶
Map the user-side role-assignment collection.
Returns:
| Type | Description |
|---|---|
Mapped[list[Any]]
|
The relationship descriptor for role-assignment rows. |
Source code in litestar_auth/_auth_model_mixins.py
__dir__()
¶
__getattr__(name)
¶
Load lazy model exports on demand.
Returns:
| Type | Description |
|---|---|
object
|
The requested ORM model or mixin. |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If |
Source code in litestar_auth/models/__init__.py
import_token_orm_models()
¶
Return all bundled token ORM models for explicit and plugin-owned bootstrap.
This remains the public helper for metadata bootstrap and Alembic-style
autogenerate flows. LitestarAuth.on_app_init() also calls it lazily when bundled
DB-token models are active, so plugin-managed runtime no longer depends on a separate
app-level import side effect. The helper keeps token-model discovery under
litestar_auth.models without importing the reference User mapper.