TOTP¶
Use this page for TotpConfig fields and the plugin-owned TOTP route contract.
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; supported values are "SHA256" and "SHA512". |
totp_pending_jti_store |
None |
JWT JTI denylist for pending login tokens. Required unless the owning config/controller explicitly sets unsafe_testing=True. Use a shared store such as RedisJWTDenylistStore for multi-worker deployments. |
totp_enrollment_store |
None |
Server-side pending-enrollment store. Required unless the owning config/controller explicitly sets unsafe_testing=True. Use a shared store such as RedisTotpEnrollmentStore for multi-worker deployments. |
totp_used_tokens_store |
None |
Replay store for consumed TOTP codes (required unless the owning config/controller explicitly sets unsafe_testing=True). See Redis-backed auth surface for the Redis setup and import paths. |
totp_require_replay_protection |
True |
Fail startup without a store unless unsafe_testing=True. |
totp_enable_requires_password |
True |
Step-up password for /2fa/enable. |
totp_pending_require_client_binding |
True |
Bind pending-login JWTs to hashed client IP and User-Agent fingerprints and reject mismatches at /2fa/verify. |
Routes: {auth_path}/2fa/.... See TOTP guide.
The plugin-owned TOTP flow follows LitestarAuthConfig.requires_verification, which now defaults
to True. Manual create_totp_controller(...) wiring should keep that flag aligned with the auth
controller so unverified accounts cannot complete the second authentication step. When both checks
fail, the shared account-state policy reports inactive users before unverified users.
totp_pending_secret signs pending-2FA JWTs for the controller flow. It is separate from
user_manager_security.totp_secret_keyring, which encrypts the TOTP secret at rest on the user
record and before writing the short-lived pending-enrollment secret to
totp_enrollment_store. The enrollment JWT returned by /2fa/enable carries only lookup claims,
not the secret. The plugin forwards the configured keyring into
create_totp_controller(..., totp_secret_keyring=...) automatically. In production,
totp_secret_keyring or the one-key totp_secret_key shortcut is required —
create_totp_controller fails closed with ConfigurationError when both are omitted and
unsafe_testing=False. Persisted user-row TOTP secrets are stored as
fernet:v1:<key_id>:<ciphertext> values and unprefixed plaintext rows are rejected fail-closed.
Use BaseUserManager.totp_secret_requires_reencrypt(...) and
BaseUserManager.reencrypt_totp_secret_for_storage(...) from migration code that rewrites stored
values under the active configured key.
For rotation, add a new Fernet key id to user_manager_security.totp_secret_keyring.keys, deploy the
expanded keyring first, then switch active_key_id to the new id. New pending-enrollment and
persisted TOTP writes use the new key id while old versioned rows remain readable. An
application-owned migration can scan persisted TOTP secret values, call
BaseUserManager.totp_secret_requires_reencrypt(value), and rewrite only values that return True
through BaseUserManager.reencrypt_totp_secret_for_storage(value). Verify a final scan before
removing the retired key id. The full staged checklist is in
Deployment.
Legacy unversioned Fernet values are migration input only because they do not carry a key id. They
must be decrypted with explicit old key material and rewritten to fernet:v1:<key_id>:<ciphertext>.
Plaintext persisted TOTP rows remain unsupported and fail closed; clear or encrypt them before
production use.
If totp_backend_name is omitted, the plugin uses the primary startup backend. Set a backend name
only when a secondary startup backend should issue post-2FA tokens.
Pending-token JTI store
The plugin-owned controller forwards TotpConfig.totp_pending_jti_store into create_totp_controller(..., pending_jti_store=...). In production, missing pending-token replay storage now fails closed unless unsafe_testing=True.
Pending-token client binding
The plugin-owned auth and TOTP controllers both forward TotpConfig.totp_pending_require_client_binding. Keep the default True unless your proxy topology cannot provide stable client metadata and you accept pending-token replay from a different client. The fingerprints are SHA-256 hex values, not raw IP or User-Agent strings.
Pending-enrollment store
The plugin-owned controller forwards TotpConfig.totp_enrollment_store into create_totp_controller(..., enrollment_store=...). In production, missing enrollment storage now fails closed unless unsafe_testing=True; each /2fa/enable replaces the previous pending enrollment for that user, and /2fa/enable/confirm consumes the matching jti once.