better_auth_api/plugins/password_management/
callbacks.rs1use super::{PasswordManagementConfig, PasswordManagementPlugin};
2use crate::plugins::endpoint_context::{EndpointContext, WithCallbacks};
3use better_auth_core::{
4 AuthContext, AuthError, AuthPlugin, AuthResult, AuthSchema, background::BackgroundFuture,
5 wire::UserView,
6};
7use std::sync::Arc;
8
9#[derive(Clone)]
11pub struct PasswordResetEmail {
12 pub user: UserView,
14 pub url: String,
16 pub token: String,
18}
19
20type Sender<S> = dyn Fn(&PasswordResetEmail, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
21 + Send
22 + Sync;
23
24pub struct PasswordManagementCallbacks<S: AuthSchema> {
26 sender: Arc<Sender<S>>,
27}
28impl<S: AuthSchema> PasswordManagementCallbacks<S> {
29 pub fn send_reset_password(
32 callback: impl Fn(
33 &PasswordResetEmail,
34 &EndpointContext<'_, S>,
35 ) -> AuthResult<Option<BackgroundFuture>>
36 + Send
37 + Sync
38 + 'static,
39 ) -> Self {
40 Self {
41 sender: Arc::new(callback),
42 }
43 }
44}
45impl PasswordManagementPlugin {
46 pub fn callbacks<S: AuthSchema>(
48 self,
49 callbacks: PasswordManagementCallbacks<S>,
50 ) -> impl AuthPlugin<S> {
51 WithCallbacks {
52 plugin: self,
53 callbacks: Arc::new(callbacks),
54 }
55 }
56}
57
58pub(super) fn require_sender<S: AuthSchema>(
59 config: &PasswordManagementConfig,
60 ctx: &AuthContext<S>,
61) -> AuthResult<()> {
62 if config.send_reset_password.is_none()
63 && ctx
64 .extensions
65 .get::<Arc<PasswordManagementCallbacks<S>>>()
66 .is_none()
67 {
68 return Err(AuthError::bad_request("Reset password isn't enabled"));
69 }
70 Ok(())
71}
72
73pub(super) fn delivery<S: AuthSchema>(
74 config: &PasswordManagementConfig,
75 email: PasswordResetEmail,
76 endpoint: &EndpointContext<'_, S>,
77) -> AuthResult<Option<BackgroundFuture>> {
78 if let Some(callbacks) = endpoint
79 .auth
80 .extensions
81 .get::<Arc<PasswordManagementCallbacks<S>>>()
82 {
83 return (callbacks.sender)(&email, endpoint);
84 }
85 let sender = config
86 .send_reset_password
87 .clone()
88 .ok_or_else(|| AuthError::bad_request("Reset password isn't enabled"))?;
89 let user = serde_json::to_value(email.user)?;
90 let request = endpoint.request.cloned();
91 Ok(Some(Box::pin(async move {
92 sender
93 .send_with_request(&user, &email.url, &email.token, request.as_ref())
94 .await
95 })))
96}