Password configuration
PasswordConfig defines the hashing and verification strategy for the entire application. It is initialized once at startup via password_init().
Initialization in `main.rs`
use runique::prelude::{password_init, PasswordConfig, Manual};
#[tokio::main]
async fn main() {
// Argon2 automatic mode (recommended default)
password_init(PasswordConfig::auto());
RuniqueApp::builder(config)
// ...
.run()
.await;
}
If
password_init()is not called, Argon2 is used by default.
Available modes
Auto — Automatic hashing (recommended)
Runique detects whether a value is already hashed and only hashes it once. The algorithm is configurable.
// Argon2 by default
password_init(PasswordConfig::auto());
// Choose the algorithm
password_init(PasswordConfig::auto_with(Manual::Bcrypt));
password_init(PasswordConfig::auto_with(Manual::Scrypt));
Supported algorithms: Manual::Argon2, Manual::Bcrypt, Manual::Scrypt.
Manual — Explicit hashing
Hashing is not applied automatically in finalize(). The developer calls hash() manually.
password_init(PasswordConfig::manual(Manual::Argon2));
Use this when you need precise control over when and how the password is hashed.
Built-in reset and admin: the built-in reset route (
with_password_reset) hashes the new password itself with the app's configuration, whatever the mode (Auto,ManualorCustom). InDelegatedmode, it refuses the reset: no local password is written, and the link stays usable. An account created from the admin gets a random password, hashed the same way, then a link to choose its own.In your own forms, however,
finalize()only hashes inAutomode: inManualorCustom, callhash()before writing to the database.
Delegated — External authentication (OAuth / SSO)
No local password is managed by Runique: verify() always answers false, hash() fails, and the built-in reset is refused.
This mode doesn't provide the external authentication itself yet. The providers below are only names: Runique implements today neither the OAuth flow (redirect, code exchange, profile reading), nor LDAP, nor SAML.
Delegatedis there to switch local passwords off cleanly when your app handles sign-in by other means (an OAuth library, an authentication proxy), then opens the session withlogin(&request.session, &user, None, false)once the user is identified. Full provider integration is a planned evolution.
use runique::prelude::External;
password_init(PasswordConfig::Delegated(External::GoogleOAuth));
password_init(PasswordConfig::Delegated(External::Microsoft));
password_init(PasswordConfig::Delegated(External::Ldap("ldap://...".to_string())));
Available providers: GoogleOAuth, Microsoft, Apple, Ldap(url), Saml(url), Custom { name, authorize_url, token_url }.
Custom — Custom handler
Implement the PasswordHandler trait to plug in your own hashing/verification logic.
use runique::prelude::{PasswordHandler, PasswordConfig};
#[derive(Clone)] // required: PasswordHandler is cloned with the config
struct MyHasher;
impl PasswordHandler for MyHasher {
fn name(&self) -> &str { "my_hasher" }
fn create_field(&self, name: &str) -> Box<dyn runique::forms::FormField> {
Box::new(runique::forms::fields::text::TextField::password(name))
}
fn validate_input(&self, input: &str) -> Result<(), String> {
if input.len() < 8 { Err("Too short".into()) } else { Ok(()) }
}
fn transform(&self, input: &str) -> Result<String, String> {
my_algo::hash(input).map_err(|e| e.to_string())
}
fn verify(&self, input: &str, stored: &str) -> bool {
// The comparison must run in constant time (the algorithm's own
// verify function, or `ct_eq`), never with `==`.
my_algo::verify(input, stored)
}
}
password_init(PasswordConfig::custom(MyHasher));
Usage in code
use runique::prelude::{hash, verify};
// Hash a password (uses the global config)
let hashed = hash("my_password")?;
// Verify a password against a stored hash
let ok = verify("my_password", &user.password);
These functions automatically use the PasswordConfig initialized at startup.
In forms
TextField::password() fields are automatically hashed in finalize() in Auto mode. In Manual or Custom mode, no automatic hashing occurs: call hash() yourself. A field marked .no_hash() is never hashed (a sign-in form compares the password as typed, with authenticate_user).
In Auto mode, a password hashed with another algorithm than the configured one is moved to it on the first successful sign-in.
See → Field types — TextField
← Builder