Password Management
Forget, reset, and change passwords.
The PasswordManagementPlugin provides endpoints for password reset flows, password changes, and current-password verification.
Password reset and change use AuthConfig.password.min_length and max_length, which default to 8 and 128 UTF-16 code units. The default hasher applies NFKC normalization before hashing and verification. Custom PasswordHasher implementations receive the original password.
Reset tokens are consumed atomically. Concurrent requests using one token can reset the password only once. An invalid password length does not consume the token.
Before upgrading an existing installation, identify password hashes created from non-NFKC input. Those users must reset their passwords; default verification does not retry the previous unnormalized input.
Setup
These examples assume you've already defined AppAuthSchema. If you want a complete setup from entity definitions through Axum mounting, start with the Axum integration guide.
use std::sync::Arc;
use better_auth::plugins::{
PasswordManagementPlugin,
password_management::SendResetPassword,
};
struct ResetSender;
#[async_trait::async_trait]
impl SendResetPassword for ResetSender {
async fn send(
&self,
user: &serde_json::Value,
url: &str,
token: &str,
) -> better_auth::AuthResult<()> {
let _ = (user, url, token);
Ok(())
}
}
let auth = BetterAuth::<AppAuthSchema>::new(config)
.store(store)
.plugin(
PasswordManagementPlugin::new()
.reset_token_expiry_hours(24)
.require_current_password(true)
.send_reset_password(Arc::new(ResetSender))
)
.build()
.await?;Plugin Options
| Option | Type | Default | Description |
|---|---|---|---|
reset_token_expiry_hours | i64 | 24 | Hours before reset token expires |
require_current_password | bool | true | Require current password for changes |
send_email_notifications | bool | true | Send email on password changes |
Forget Password
Initiates a password reset flow.
This endpoint requires PasswordManagementPlugin::send_reset_password(...).
Configuring a global EmailProvider alone does not enable
POST /request-password-reset.
POST /request-password-reset
Content-Type: application/json{
"email": "[email protected]",
"redirectTo": "https://example.com/reset"
}Response
{
"status": true
}Always returns success regardless of whether the email exists (prevents enumeration).
Reset Password
Completes the password reset using a token from the email link.
POST /reset-password
Content-Type: application/json{
"newPassword": "new_secure_password",
"token": "reset_token_from_email"
}Response
{
"user": { ... }
}| Status | Condition |
|---|---|
| 400 | Token missing or expired, password too short |
Validate Reset Token
Check if a reset token is still valid before showing the reset form.
GET /reset-password/{token}Returns 200 if valid, 400 if expired or invalid.
Change Password (Authenticated)
Change password for the currently signed-in user.
POST /change-password
Authorization: Bearer <token>
Content-Type: application/json{
"currentPassword": "old_password",
"newPassword": "new_password",
"revokeOtherSessions": "true"
}| Field | Required | Description |
|---|---|---|
currentPassword | Yes | Current password for verification |
newPassword | Yes | New password (must meet policy) |
revokeOtherSessions | No | Revoke all other sessions after change |
Response
{
"user": { ... },
"token": "session_new..."
}Verify Password (Authenticated)
Verify the current user's password before a sensitive action.
POST /verify-password
Authorization: Bearer <token>
Content-Type: application/json{
"password": "current_password"
}Response
{
"status": true
}For users without a credential password, this endpoint returns the same
Invalid password error as an incorrect password.