supabase_auth_redux/delete_user.rs
1use crate::util::handle_response_code;
2use crate::AuthClient;
3use crate::AuthError;
4use serde::{Deserialize, Serialize};
5use tracing::{debug, instrument};
6use uuid::Uuid;
7
8#[derive(Debug, Deserialize, Serialize)]
9struct DeleteBody {
10 should_soft_delete: bool,
11}
12
13impl AuthClient {
14 /// Soft deletes a user, marking them as deleted but preserving their data
15 ///
16 /// This operation requires a service role key to be configured on the AuthClient.
17 /// The user will be marked as deleted but their data will be retained in the database.
18 ///
19 /// # Arguments
20 ///
21 /// * `user_id` - The UUID of the user to soft delete
22 ///
23 /// # Errors
24 ///
25 /// Returns `AuthError::ServiceRoleKeyRequired` if no service role key is configured.
26 /// Returns `AuthError::Http` if the API request fails.
27 ///
28 /// # Example
29 ///
30 /// ```rust,no_run
31 /// # use supabase_auth_redux::AuthClient;
32 /// # use uuid::Uuid;
33 /// # async fn example() -> Result<(), supabase_auth_redux::AuthError> {
34 /// let admin_client = AuthClient::builder()
35 /// .api_url("https://your-project.supabase.co")
36 /// .anon_key("your-anon-key")
37 /// .service_role_key("your-service-role-key")
38 /// .build()?;
39 ///
40 /// let user_id = Uuid::parse_str("123e4567-e89b-12d3-a456-426614174000").unwrap();
41 /// admin_client.soft_delete_user(user_id).await?;
42 /// # Ok(())
43 /// # }
44 /// ```
45 #[instrument(skip_all)]
46 pub async fn soft_delete_user(&self, user_id: Uuid) -> Result<(), AuthError> {
47 let service_role_key = self
48 .supabase_service_role_key
49 .as_ref()
50 .ok_or(AuthError::ServiceRoleKeyRequired)?;
51
52 let resp = match self
53 .http_client
54 .delete(format!(
55 "{}/auth/v1/admin/users/{}",
56 self.supabase_api_url, user_id
57 ))
58 .json(&DeleteBody {
59 should_soft_delete: true,
60 })
61 .bearer_auth(service_role_key)
62 .header("apiKey", service_role_key)
63 .send()
64 .await
65 {
66 Ok(resp) => resp,
67 Err(e) => {
68 debug!("{}", e);
69 return Err(AuthError::Http);
70 }
71 };
72
73 let resp_code_result = handle_response_code(resp.status()).await;
74 let resp_text = match resp.text().await {
75 Ok(resp_text) => resp_text,
76 Err(e) => {
77 log::error!("{}", e);
78 return Err(AuthError::Http);
79 }
80 };
81 debug!("resp_text: {}", resp_text);
82 resp_code_result
83 }
84
85 /// Permanently deletes a user and all their associated data
86 ///
87 /// This operation requires a service role key to be configured on the AuthClient.
88 /// The user and all their data will be permanently removed from the database.
89 /// This action cannot be undone.
90 ///
91 /// # Arguments
92 ///
93 /// * `user_id` - The UUID of the user to permanently delete
94 ///
95 /// # Errors
96 ///
97 /// Returns `AuthError::ServiceRoleKeyRequired` if no service role key is configured.
98 /// Returns `AuthError::Http` if the API request fails.
99 ///
100 /// # Example
101 ///
102 /// ```rust,no_run
103 /// # use supabase_auth_redux::AuthClient;
104 /// # use uuid::Uuid;
105 /// # async fn example() -> Result<(), supabase_auth_redux::AuthError> {
106 /// let admin_client = AuthClient::builder()
107 /// .api_url("https://your-project.supabase.co")
108 /// .anon_key("your-anon-key")
109 /// .service_role_key("your-service-role-key")
110 /// .build()?;
111 ///
112 /// let user_id = Uuid::parse_str("123e4567-e89b-12d3-a456-426614174000").unwrap();
113 /// admin_client.hard_delete_user(user_id).await?;
114 /// # Ok(())
115 /// # }
116 /// ```
117 #[instrument(skip_all)]
118 pub async fn hard_delete_user(&self, user_id: Uuid) -> Result<(), AuthError> {
119 let service_role_key = self
120 .supabase_service_role_key
121 .as_ref()
122 .ok_or(AuthError::ServiceRoleKeyRequired)?;
123
124 let resp = match self
125 .http_client
126 .delete(format!(
127 "{}/auth/v1/admin/users/{}",
128 self.supabase_api_url, user_id
129 ))
130 .json(&DeleteBody {
131 should_soft_delete: false,
132 })
133 .bearer_auth(service_role_key)
134 .header("apiKey", service_role_key)
135 .send()
136 .await
137 {
138 Ok(resp) => resp,
139 Err(e) => {
140 debug!("{}", e);
141 return Err(AuthError::Http);
142 }
143 };
144
145 let resp_code_result = handle_response_code(resp.status()).await;
146 let resp_text = match resp.text().await {
147 Ok(resp_text) => resp_text,
148 Err(e) => {
149 log::error!("{}", e);
150 return Err(AuthError::Http);
151 }
152 };
153 debug!("resp_text: {}", resp_text);
154 resp_code_result
155 }
156}