Password reset¶
Password reset is opt-in. You enable it by providing an async function that sends the reset email.
Setup¶
async def send_reset_email(email: str, token: str) -> None:
"""Send a password reset email. Called by bluefox-auth."""
reset_url = f"https://app.example.com/reset-password?token={token}"
await your_email_service.send(
to=email,
subject="Reset your password",
body=f"Click here to reset your password: {reset_url}",
)
BluefoxAuth(app, settings, password_reset_send_fn=send_reset_email)
The function receives the user's email and a signed JWT token (valid for 1 hour). Without this hook, the /password-reset endpoint returns 501 Not Implemented.
Flow¶
1. User requests a reset¶
Response (always the same, regardless of whether the email exists):
This prevents email enumeration. If the email is unknown or the user is inactive, no email is sent.
2. User confirms the reset¶
The user clicks the link in the email, your frontend collects the new password, and sends:
POST /auth/password-reset/confirm
Content-Type: application/json
{"token": "eyJhbG...", "new_password": "my-new-strong-password"}
Response:
Security¶
- One-time use — once the password is changed, the token cannot be reused. This is enforced by checking
updated_at > created_at(the user record was modified after initial creation) andupdated_at >= iat(the modification happened after the token was issued). - 1 hour expiry — tokens expire after 60 minutes
- Type-checked — a password reset token cannot be used for email verification, and vice versa
- Silent on unknown email — prevents user enumeration
Frontend example¶
// Request reset
await fetch("/auth/password-reset", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: userEmail }),
});
// Confirm reset (after user clicks email link)
const token = new URLSearchParams(window.location.search).get("token");
await fetch("/auth/password-reset/confirm", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token, new_password: newPassword }),
});