Files
windmill/backend/windmill-api/src/users_oss.rs
claude[bot] 6f7cf2fb16 feat: add password reset flow using configured SMTP settings (#7525)
* feat: add password reset flow using configured SMTP settings

Implements password reset functionality for users with email/password login:

Backend:
- Add `/auth/request_password_reset` endpoint to request a password reset email
- Add `/auth/reset_password` endpoint to reset password using token
- Add `/auth/is_smtp_configured` endpoint to check if SMTP is available
- Uses existing `magic_link` table for storing reset tokens
- Tokens expire after 1 hour
- Invalidates all existing sessions on password reset
- Includes audit logging

Frontend:
- Add "Forgot password?" link on login page (shown when SMTP is configured)
- Add `/user/forgot-password` page for requesting password reset
- Add `/user/reset-password` page for entering new password
- Both pages follow existing Windmill design patterns

Security:
- Always returns success response to prevent email enumeration
- Password must be at least 8 characters
- Uses argon2 for password hashing (same as existing login)

Closes #7524

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>

* nits

* nits

* fix oss

* nits

* fix oss

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: HugoCasa <hugo@casademont.ch>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-01-09 10:31:56 +00:00

90 lines
2.2 KiB
Rust

#[cfg(feature = "private")]
#[allow(unused)]
pub use crate::users_ee::*;
#[cfg(not(feature = "private"))]
use std::sync::Arc;
#[cfg(not(feature = "private"))]
use crate::db::ApiAuthed;
#[cfg(not(feature = "private"))]
use crate::users::{EditPassword, NewUser};
#[cfg(not(feature = "private"))]
use crate::{db::DB, webhook_util::WebhookShared};
#[cfg(not(feature = "private"))]
use argon2::Argon2;
#[cfg(not(feature = "private"))]
use axum::{extract::Extension, Json};
#[cfg(not(feature = "private"))]
use http::StatusCode;
#[cfg(not(feature = "private"))]
use serde::Deserialize;
#[cfg(not(feature = "private"))]
use windmill_common::error::{Error, Result};
#[cfg(not(feature = "private"))]
pub async fn create_user(
_authed: ApiAuthed,
_db: DB,
_webhook: WebhookShared,
_argon2: Arc<Argon2<'_>>,
mut _nu: NewUser,
) -> Result<(StatusCode, String)> {
Err(Error::internal_err(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(not(feature = "private"))]
pub async fn set_password(
_db: DB,
_argon2: Arc<Argon2<'_>>,
_authed: ApiAuthed,
_user_email: &str,
_ep: EditPassword,
) -> Result<String> {
Err(Error::internal_err(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(not(feature = "private"))]
pub fn hash_password(_argon2: Arc<Argon2<'_>>, _password: String) -> Result<String> {
Err(Error::internal_err(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(not(feature = "private"))]
pub fn send_email_if_possible(_subject: &str, _content: &str, _to: &str) {
tracing::warn!(
"send_email_if_possible is not implemented in Windmill's Open Source repository"
);
}
#[cfg(not(feature = "private"))]
#[derive(Deserialize, Debug)]
#[allow(dead_code)]
pub struct OnboardingData {
pub touch_point: String,
pub use_case: String,
}
#[cfg(not(feature = "private"))]
pub async fn submit_onboarding_data(
_authed: ApiAuthed,
Extension(_db): Extension<DB>,
Json(_data): Json<OnboardingData>,
) -> Result<String> {
Err(Error::internal_err(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}