howdy/auth/mfa
Optional second-factor configuration. Keep the encryption key outside the
auth database; all nodes must use the same stable, 32-byte base64url key.
Rotate it with with_decryption_keys and auth.reseal_mfa.
Types
Values
pub const default_trust_seconds: Int
Default remembered-device lifetime: 30 days.
pub fn new(
issuer: String,
encryption_key: String,
) -> Result(Config, service.Error)
pub fn with_decryption_keys(
config: Config,
keys: List(String),
) -> Result(Config, service.Error)
Keys that still decrypt authenticator secrets but never encrypt new ones, replacing any given before. To rotate without failing a sign-in:
- On every node, add the new key here, keeping the old key in
new. - On every node, swap them: the new key in
new, the old key here. - Run
auth.reseal_mfaonce, then drop the old key.
The first step lets a node still sealing with the old key read what an updated node seals; skip it only if all nodes restart together.
pub fn with_delivery(
config: Config,
deliver: fn(user.User, secret.Secret) -> Result(Nil, Nil),
) -> Config
Deliver to a separately verified channel owned by this user. The application chooses the address/phone; never take the destination from the login request. An email-token login cannot use delivered OTP as its second factor.
pub fn with_device_trust(
config: Config,
seconds seconds: Int,
renew renew: Bool,
) -> Result(Config, service.Error)
How long a remembered device skips the second factor: 30 days by default,
at least five minutes and at most a year. With renew, each successful use
restarts the lifetime, so only a device left unused this long is forgotten;
without it, trust ends this long after the second factor was last verified.
Devices already remembered keep the expiry they were issued with.
pub fn with_recovery_codes(
config: Config,
count: Int,
) -> Result(Config, service.Error)
Recovery codes issued per enrollment or regeneration: 10 by default, 4 to 32.