diff --git a/README.md b/README.md index c78d25e..9bb2dda 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ - [x] Logout - [x] Verify one-time token - [ ] Authorize external OAuth provicder -- [ ] Password recovery +- [x] Password recovery - [x] Resend one-time password over email or SMS - [ ] Magic link authentication - [x] One-time password authentication diff --git a/src/auth.rs b/src/auth.rs index a3245f2..7ed16ee 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -35,6 +35,11 @@ impl std::fmt::Display for LogoutError { impl std::error::Error for LogoutError {} +#[derive(Serialize)] +struct RecoverRequest<'a> { + email: &'a str, +} + #[derive(Serialize)] struct PhoneCredentials<'a> { phone: &'a str, @@ -122,6 +127,19 @@ impl Supabase { .await) } + /// Sends a password recovery email to the given address. + pub async fn recover_password(&self, email: &str) -> Result { + let url = format!("{}/auth/v1/recover", self.url); + + self.client + .post(&url) + .header("apikey", &self.api_key) + .header("Content-Type", "application/json") + .json(&RecoverRequest { email }) + .send() + .await + } + /// Signs up a new user with phone and password. pub async fn signup_phone_password( &self, @@ -385,6 +403,24 @@ mod tests { assert_eq!(format!("{}", LogoutError), "bearer token required for logout"); } + #[tokio::test] + async fn test_recover_password() { + let client = client(); + + let response = match client + .recover_password("test@a-rust-domain-that-does-not-exist.com") + .await + { + Ok(resp) => resp, + Err(e) => { + println!("Test skipped due to network error: {e}"); + return; + } + }; + + let _status = response.status(); + } + #[tokio::test] async fn test_signup_phone_password() { let client = client();