Skip to content

User manager

litestar_auth.manager

User-management business logic for litestar-auth.

BaseUserManager(user_db, *, oauth_account_store=None, password_helper=None, verification_token_secret=None, reset_password_token_secret=None, verification_token_lifetime=DEFAULT_VERIFY_TOKEN_LIFETIME, reset_password_token_lifetime=DEFAULT_RESET_PASSWORD_TOKEN_LIFETIME, id_parser=None, password_validator=None, reset_verification_on_email_change=True, totp_secret_key=None, backends=(), login_identifier='email')

Bases: _UserLifecycleManagerProtocol[UP, ID], _AccountTokensManagerProtocol[UP, ID], _TotpSecretsManagerProtocol[UP]

Coordinate user persistence, password hashing, and account tokens.

Initialize the user manager.

Parameters:

Name Type Description Default
user_db BaseUserStore[UP, ID]

Persistence backend used to load and update users.

required
oauth_account_store BaseOAuthAccountStore[UP, ID] | None

Optional persistence backend used for linked OAuth accounts.

None
password_helper PasswordHelper | None

Password hasher/verifier implementation.

None
verification_token_secret str | None

Secret used to sign email-verification tokens. If omitted, ConfigurationError is raised unless LITESTAR_AUTH_TESTING=1.

None
reset_password_token_secret str | None

Secret used to sign password-reset tokens. If omitted, ConfigurationError is raised unless LITESTAR_AUTH_TESTING=1.

None
verification_token_lifetime timedelta

Lifetime applied to verification tokens.

DEFAULT_VERIFY_TOKEN_LIFETIME
reset_password_token_lifetime timedelta

Lifetime applied to password-reset tokens.

DEFAULT_RESET_PASSWORD_TOKEN_LIFETIME
id_parser Callable[[str], ID] | None

Optional callable that converts JWT sub strings into user identifiers.

None
password_validator Callable[[str], None] | None

Optional callable used to validate plain-text passwords.

None
reset_verification_on_email_change bool

Whether email changes should clear is_verified and trigger a new verification token hook.

True
totp_secret_key str | None

Optional Fernet key used to encrypt stored TOTP secrets.

None
backends tuple[object, ...]

Session-bound auth backends when constructed via LitestarAuth; keeps credential updates aligned with the same backends used for request auth.

()
login_identifier LoginIdentifier

Which field authenticate uses for credential lookup by default when login_identifier is not passed explicitly to authenticate.

'email'
Source code in litestar_auth/manager.py
def __init__(  # noqa: PLR0913
    self: BaseUserManager[UP, ID],
    user_db: BaseUserStore[UP, ID],
    *,
    oauth_account_store: BaseOAuthAccountStore[UP, ID] | None = None,
    password_helper: PasswordHelper | None = None,
    verification_token_secret: str | None = None,
    reset_password_token_secret: str | None = None,
    verification_token_lifetime: timedelta = DEFAULT_VERIFY_TOKEN_LIFETIME,
    reset_password_token_lifetime: timedelta = DEFAULT_RESET_PASSWORD_TOKEN_LIFETIME,
    id_parser: Callable[[str], ID] | None = None,
    password_validator: Callable[[str], None] | None = None,
    reset_verification_on_email_change: bool = True,
    totp_secret_key: str | None = None,
    backends: tuple[object, ...] = (),
    login_identifier: LoginIdentifier = "email",
) -> None:
    """Initialize the user manager.

    Args:
        user_db: Persistence backend used to load and update users.
        oauth_account_store: Optional persistence backend used for linked OAuth accounts.
        password_helper: Password hasher/verifier implementation.
        verification_token_secret: Secret used to sign email-verification tokens.
            If omitted, ``ConfigurationError`` is raised unless ``LITESTAR_AUTH_TESTING=1``.
        reset_password_token_secret: Secret used to sign password-reset tokens.
            If omitted, ``ConfigurationError`` is raised unless ``LITESTAR_AUTH_TESTING=1``.
        verification_token_lifetime: Lifetime applied to verification tokens.
        reset_password_token_lifetime: Lifetime applied to password-reset tokens.
        id_parser: Optional callable that converts JWT ``sub`` strings into user identifiers.
        password_validator: Optional callable used to validate plain-text passwords.
        reset_verification_on_email_change: Whether email changes should clear ``is_verified`` and
            trigger a new verification token hook.
        totp_secret_key: Optional Fernet key used to encrypt stored TOTP secrets.
        backends: Session-bound auth backends when constructed via ``LitestarAuth``;
            keeps credential updates aligned with the same backends used for request auth.
        login_identifier: Which field ``authenticate`` uses for credential lookup by default
            when ``login_identifier`` is not passed explicitly to ``authenticate``.

    """
    verification_token_secret = _resolve_token_secret(
        verification_token_secret,
        label="verification_token_secret",
        warning_stacklevel=3,
    )
    reset_password_token_secret = _resolve_token_secret(
        reset_password_token_secret,
        label="reset_password_token_secret",
        warning_stacklevel=3,
    )
    self.user_db = user_db
    self.oauth_account_store = oauth_account_store or _resolve_oauth_account_store(user_db)
    self.password_helper = password_helper or PasswordHelper()
    self.verification_token_secret = _SecretValue(verification_token_secret)
    self.reset_password_token_secret = _SecretValue(reset_password_token_secret)
    self.verification_token_lifetime = verification_token_lifetime
    self.reset_password_token_lifetime = reset_password_token_lifetime
    self.id_parser = id_parser
    self.password_validator = password_validator
    self.reset_verification_on_email_change = reset_verification_on_email_change
    self.totp_secret_key = totp_secret_key
    self.backends: tuple[object, ...] = backends
    self.login_identifier: LoginIdentifier = login_identifier
    self.policy = UserPolicy(
        password_helper=self.password_helper,
        password_validator=self.password_validator,
    )
    self._user_lifecycle = UserLifecycleService(self, policy=self.policy)
    self._account_token_security = AccountTokenSecurityService(
        self,
        logger=logger,
        reset_password_token_audience=RESET_PASSWORD_TOKEN_AUDIENCE,
    )
    self._account_tokens = AccountTokensService(
        self,
        verify_token_audience=VERIFY_TOKEN_AUDIENCE,
        reset_password_token_audience=RESET_PASSWORD_TOKEN_AUDIENCE,
        token_security=self._account_token_security,
        logger=logger,
    )
    self._totp_secrets = TotpSecretsService(self, prefix=ENCRYPTED_TOTP_SECRET_PREFIX)

authenticate(identifier, password, *, login_identifier=None) async

Return the matching user when credentials are valid.

After successful verification, if the stored hash is deprecated (e.g. bcrypt), the password hash is upgraded to the current algorithm (e.g. Argon2) in the DB. If the DB update fails, login still succeeds without upgrading the hash.

Parameters:

Name Type Description Default
identifier str

Email or username string, depending on login_identifier.

required
password str

Plain-text password.

required
login_identifier LoginIdentifier | None

Lookup mode; defaults to :attr:login_identifier on this manager.

None
Source code in litestar_auth/manager.py
async def authenticate(
    self,
    identifier: str,
    password: str,
    *,
    login_identifier: LoginIdentifier | None = None,
) -> UP | None:
    """Return the matching user when credentials are valid.

    After successful verification, if the stored hash is deprecated (e.g. bcrypt),
    the password hash is upgraded to the current algorithm (e.g. Argon2) in the DB.
    If the DB update fails, login still succeeds without upgrading the hash.

    Args:
        identifier: Email or username string, depending on ``login_identifier``.
        password: Plain-text password.
        login_identifier: Lookup mode; defaults to :attr:`login_identifier` on this manager.
    """
    mode = login_identifier if login_identifier is not None else self.login_identifier
    user = await self._user_lifecycle.authenticate(
        identifier,
        password,
        login_identifier=mode,
        dummy_hash=_get_dummy_hash(),
        logger=logger,
    )
    if user is None:
        logger.warning("User login failed", extra={"event": "login_failed"})
        return None

    logger.info("User login succeeded", extra={"event": "login", "user_id": str(user.id)})
    return user

create(user_create, *, safe=True, allow_privileged=False) async

Create a new user, hashing the provided password before persistence.

Returns:

Type Description
UP

The newly created user.

Source code in litestar_auth/manager.py
async def create(
    self,
    user_create: msgspec.Struct | Mapping[str, Any],
    *,
    safe: bool = True,
    allow_privileged: bool = False,
) -> UP:
    """Create a new user, hashing the provided password before persistence.

    Returns:
        The newly created user.
    """
    user = await self._user_lifecycle.create(user_create, safe=safe, allow_privileged=allow_privileged)
    logger.info("User registered", extra={"event": "register", "user_id": str(user.id)})
    return user

delete(user_id) async

Delete a user permanently and run the post-delete hook.

Source code in litestar_auth/manager.py
async def delete(self, user_id: ID) -> None:
    """Delete a user permanently and run the post-delete hook."""
    await self._user_lifecycle.delete(user_id)

forgot_password(email) async

Trigger the forgot-password flow without revealing whether a user exists.

Source code in litestar_auth/manager.py
async def forgot_password(self, email: str) -> None:
    """Trigger the forgot-password flow without revealing whether a user exists."""
    await self._account_tokens.forgot_password(email, dummy_hash=_get_dummy_hash())

get(user_id) async

Return a user by identifier.

Returns:

Type Description
UP | None

The matching user when one exists, otherwise None.

Source code in litestar_auth/manager.py
async def get(self, user_id: ID) -> UP | None:
    """Return a user by identifier.

    Returns:
        The matching user when one exists, otherwise ``None``.
    """
    return await self._user_lifecycle.get(user_id)

list_users(*, offset, limit) async

Return paginated users and the total available count.

Source code in litestar_auth/manager.py
async def list_users(self, *, offset: int, limit: int) -> tuple[list[UP], int]:
    """Return paginated users and the total available count."""
    return await self._user_lifecycle.list_users(offset=offset, limit=limit)

on_after_delete(user) async

Hook invoked after a user is deleted permanently.

Source code in litestar_auth/manager.py
async def on_after_delete(self, user: UP) -> None:  # noqa: PLR6301
    """Hook invoked after a user is deleted permanently."""
    del user

on_after_forgot_password(user, token) async

Hook invoked after a forgot-password request is processed.

SECURITY: When user is None, the email did not match any account. To prevent user enumeration via timing, your implementation MUST perform equivalent I/O in both cases (e.g., always enqueue a background task, whether or not an email will actually be sent). Do NOT conditionally skip work based on whether user is None.

Source code in litestar_auth/manager.py
async def on_after_forgot_password(  # noqa: PLR6301
    self,
    user: UP | None,
    token: str | None,
) -> None:
    """Hook invoked after a forgot-password request is processed.

    SECURITY: When ``user`` is ``None``, the email did not match any account.
    To prevent user enumeration via timing, your implementation MUST perform
    equivalent I/O in both cases (e.g., always enqueue a background task,
    whether or not an email will actually be sent). Do NOT conditionally
    skip work based on whether ``user`` is ``None``.
    """
    del user
    del token

on_after_login(user) async

Hook invoked after a user authenticates successfully.

Source code in litestar_auth/manager.py
async def on_after_login(self, user: UP) -> None:  # noqa: PLR6301
    """Hook invoked after a user authenticates successfully."""
    del user

on_after_register(user, token) async

Hook invoked after a new user is created.

Source code in litestar_auth/manager.py
async def on_after_register(self, user: UP, token: str) -> None:  # noqa: PLR6301
    """Hook invoked after a new user is created."""
    del user
    del token

on_after_request_verify_token(user, token) async

Hook invoked after a verification token is requested.

Source code in litestar_auth/manager.py
async def on_after_request_verify_token(self, user: UP, token: str) -> None:  # noqa: PLR6301
    """Hook invoked after a verification token is requested."""
    del user
    del token

on_after_reset_password(user) async

Hook invoked after a password reset completes.

Source code in litestar_auth/manager.py
async def on_after_reset_password(self, user: UP) -> None:  # noqa: PLR6301
    """Hook invoked after a password reset completes."""
    del user

on_after_update(user, update_dict) async

Hook invoked after a user is updated successfully.

Source code in litestar_auth/manager.py
async def on_after_update(self, user: UP, update_dict: dict[str, Any]) -> None:  # noqa: PLR6301
    """Hook invoked after a user is updated successfully."""
    del user
    del update_dict

on_after_verify(user) async

Hook invoked after a user verifies their email.

Source code in litestar_auth/manager.py
async def on_after_verify(self, user: UP) -> None:  # noqa: PLR6301
    """Hook invoked after a user verifies their email."""
    del user

on_before_delete(user) async

Hook invoked before a user is deleted. Raise to cancel deletion.

Source code in litestar_auth/manager.py
async def on_before_delete(self, user: UP) -> None:  # noqa: PLR6301
    """Hook invoked before a user is deleted. Raise to cancel deletion."""
    del user

read_totp_secret(secret) async

Return a plain-text TOTP secret from storage.

Returns:

Type Description
str | None

Plain-text secret, or None when 2FA is disabled.

Source code in litestar_auth/manager.py
async def read_totp_secret(self, secret: str | None) -> str | None:
    """Return a plain-text TOTP secret from storage.

    Returns:
        Plain-text secret, or ``None`` when 2FA is disabled.
    """
    return await self._totp_secrets.read_secret(secret, load_cryptography_fernet=_load_cryptography_fernet)

request_verify_token(email) async

Generate a new verification token for an existing unverified user.

Source code in litestar_auth/manager.py
async def request_verify_token(self, email: str) -> None:
    """Generate a new verification token for an existing unverified user."""
    await self._account_tokens.request_verify_token(email)

require_account_state(user, *, require_verified=False)

Validate account-state policy for authenticated flows.

Parameters:

Name Type Description Default
user UP

User to validate.

required
require_verified bool

When True, also enforce is_verified.

False
Source code in litestar_auth/manager.py
def require_account_state(self, user: UP, *, require_verified: bool = False) -> None:  # noqa: PLR6301
    """Validate account-state policy for authenticated flows.

    Args:
        user: User to validate.
        require_verified: When ``True``, also enforce ``is_verified``.
    """
    UserPolicy.require_account_state(user, require_verified=require_verified)

reset_password(token, password) async

Reset a user's password using a signed reset token.

Returns:

Type Description
UP

The updated user instance.

Source code in litestar_auth/manager.py
async def reset_password(self, token: str, password: str) -> UP:
    """Reset a user's password using a signed reset token.

    Returns:
        The updated user instance.
    """
    return await self._account_tokens.reset_password(token, password)

set_totp_secret(user, secret) async

Store or clear the TOTP secret directly, bypassing None-filtering.

Parameters:

Name Type Description Default
user UP

The user whose TOTP secret should be updated.

required
secret str | None

New secret string, or None to disable 2FA.

required

Returns:

Type Description
UP

The updated user instance.

Source code in litestar_auth/manager.py
async def set_totp_secret(self, user: UP, secret: str | None) -> UP:
    """Store or clear the TOTP secret directly, bypassing None-filtering.

    Args:
        user: The user whose TOTP secret should be updated.
        secret: New secret string, or ``None`` to disable 2FA.

    Returns:
        The updated user instance.
    """
    return await self._totp_secrets.set_secret(
        user,
        secret,
        load_cryptography_fernet=_load_cryptography_fernet,
    )

update(user_update, user) async

Update mutable user fields, hashing passwords when provided.

Fields with None values in user_update are treated as absent and will not overwrite existing data. To explicitly clear a nullable field, use a dedicated method (e.g. set_totp_secret(user, None)).

Returns:

Type Description
UP

The updated user, or the original user when there are no changes.

Source code in litestar_auth/manager.py
async def update(self, user_update: msgspec.Struct | Mapping[str, Any], user: UP) -> UP:
    """Update mutable user fields, hashing passwords when provided.

    Fields with ``None`` values in *user_update* are treated as absent and
    will **not** overwrite existing data.  To explicitly clear a nullable
    field, use a dedicated method (e.g. ``set_totp_secret(user, None)``).

    Returns:
        The updated user, or the original user when there are no changes.
    """
    return await self._user_lifecycle.update(user_update, user)

verify(token) async

Mark a user as verified using a signed verification token.

Returns:

Type Description
UP

The verified user instance.

Source code in litestar_auth/manager.py
async def verify(self, token: str) -> UP:
    """Mark a user as verified using a signed verification token.

    Returns:
        The verified user instance.
    """
    return await self._account_tokens.verify(token)

write_verify_token(user)

Return a signed email-verification token for a user.

Returns:

Type Description
str

A short-lived verification token.

Source code in litestar_auth/manager.py
def write_verify_token(self, user: UP) -> str:
    """Return a signed email-verification token for a user.

    Returns:
        A short-lived verification token.
    """
    return self._account_tokens.write_verify_token(user)