1use std::env;
17
18use reqwest::{
19 header::{self, HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE},
20 Client, Url,
21};
22use serde_json::{from_str, Value};
23
24use crate::{
25 error::{
26 Error::{self, AuthError},
27 SupabaseHTTPError,
28 },
29 models::{
30 AuthClient, AuthServerHealth, AuthServerSettings, EmailSignUpConfirmation,
31 EmailSignUpResult, ExchangeCodeForSessionPayload, IdTokenCredentials, InviteParams,
32 LoginAnonymouslyOptions, LoginAnonymouslyPayload, LoginEmailOtpParams,
33 LoginWithEmailAndPasswordPayload, LoginWithEmailOtpPayload, LoginWithOAuthOptions,
34 LoginWithPhoneAndPasswordPayload, LoginWithSSO, LogoutScope, OAuthResponse, OTPResponse,
35 Provider, RefreshSessionPayload, RequestMagicLinkPayload, ResendParams,
36 ResetPasswordForEmailPayload, ResetPasswordOptions, SendSMSOtpPayload, Session,
37 SignUpWithEmailAndPasswordPayload, SignUpWithPasswordOptions,
38 SignUpWithPhoneAndPasswordPayload, UpdatedUser, User, VerifyOtpParams, AUTH_V1,
39 },
40};
41
42impl AuthClient {
43 pub fn new(
50 project_url: impl Into<String>,
51 api_key: impl Into<String>,
52 jwt_secret: impl Into<String>,
53 ) -> Self {
54 AuthClient {
55 client: Client::new(),
56 project_url: project_url.into(),
57 api_key: api_key.into(),
58 jwt_secret: jwt_secret.into(),
59 }
60 }
61
62 pub fn new_from_env() -> Result<AuthClient, Error> {
71 let project_url = env::var("SUPABASE_URL")?;
72 let api_key = env::var("SUPABASE_API_KEY")?;
73 let jwt_secret = env::var("SUPABASE_JWT_SECRET")?;
74
75 Ok(AuthClient {
76 client: Client::new(),
77 project_url,
78 api_key,
79 jwt_secret,
80 })
81 }
82
83 pub async fn login_with_email(&self, email: &str, password: &str) -> Result<Session, Error> {
94 let payload = LoginWithEmailAndPasswordPayload { email, password };
95
96 let mut headers = header::HeaderMap::new();
97 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
98 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
99 let body = serde_json::to_string(&payload)?;
100
101 let response = self
102 .client
103 .post(format!(
104 "{}{}/token?grant_type=password",
105 self.project_url, AUTH_V1
106 ))
107 .headers(headers)
108 .body(body)
109 .send()
110 .await?;
111
112 let res_status = response.status();
113 let res_body = response.text().await?;
114
115 if let Ok(session) = from_str(&res_body) {
116 return Ok(session);
117 }
118
119 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
120 return Err(Error::AuthError {
121 status: res_status,
122 message: error.message,
123 });
124 }
125
126 Err(Error::AuthError {
128 status: res_status,
129 message: res_body,
130 })
131 }
132
133 pub async fn login_with_phone(&self, phone: &str, password: &str) -> Result<Session, Error> {
144 let payload = LoginWithPhoneAndPasswordPayload { phone, password };
145
146 let mut headers = header::HeaderMap::new();
147 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
148 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
149
150 let body = serde_json::to_string(&payload)?;
151
152 let response = self
153 .client
154 .post(format!(
155 "{}{}/token?grant_type=password",
156 self.project_url, AUTH_V1
157 ))
158 .headers(headers)
159 .body(body)
160 .send()
161 .await?;
162
163 let res_status = response.status();
164 let res_body = response.text().await?;
165
166 if let Ok(session) = from_str(&res_body) {
167 return Ok(session);
168 }
169
170 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
171 return Err(Error::AuthError {
172 status: res_status,
173 message: error.message,
174 });
175 }
176
177 Err(Error::AuthError {
179 status: res_status,
180 message: res_body,
181 })
182 }
183
184 pub async fn sign_up_with_email_and_password(
195 &self,
196 email: &str,
197 password: &str,
198 options: Option<SignUpWithPasswordOptions>,
199 ) -> Result<EmailSignUpResult, Error> {
200 let redirect_to = options
201 .as_ref()
202 .and_then(|o| o.email_redirect_to.as_deref().map(str::to_owned));
203
204 let payload = SignUpWithEmailAndPasswordPayload {
205 email,
206 password,
207 options,
208 };
209
210 let mut headers = header::HeaderMap::new();
211 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
212 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
213
214 let body = serde_json::to_string(&payload)?;
215
216 let response = self
217 .client
218 .post(format!("{}{}/signup", self.project_url, AUTH_V1))
219 .query(&[("redirect_to", redirect_to.as_deref())])
220 .headers(headers)
221 .body(body)
222 .send()
223 .await?;
224
225 let res_status = response.status();
226 let res_body = response.text().await?;
227
228 if let Ok(session) = from_str::<Session>(&res_body) {
229 return Ok(EmailSignUpResult::SessionResult(session));
230 }
231
232 if let Ok(result) = from_str::<EmailSignUpConfirmation>(&res_body) {
233 return Ok(EmailSignUpResult::ConfirmationResult(result));
234 }
235
236 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
237 return Err(Error::AuthError {
238 status: res_status,
239 message: error.message,
240 });
241 }
242
243 Err(Error::AuthError {
245 status: res_status,
246 message: res_body,
247 })
248 }
249
250 pub async fn sign_up_with_phone_and_password(
261 &self,
262 phone: &str,
263 password: &str,
264 options: Option<SignUpWithPasswordOptions>,
265 ) -> Result<Session, Error> {
266 let redirect_to = options
267 .as_ref()
268 .and_then(|o| o.email_redirect_to.as_deref().map(str::to_owned));
269
270 let payload = SignUpWithPhoneAndPasswordPayload {
271 phone,
272 password,
273 options,
274 };
275
276 let mut headers = header::HeaderMap::new();
277 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
278 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
279
280 let body = serde_json::to_string(&payload)?;
281
282 let response = self
283 .client
284 .post(format!("{}{}/signup", self.project_url, AUTH_V1))
285 .query(&[("email_redirect_to", redirect_to.as_deref())])
286 .headers(headers)
287 .body(body)
288 .send()
289 .await?;
290
291 let res_status = response.status();
292 let res_body = response.text().await?;
293
294 if let Ok(session) = from_str(&res_body) {
295 return Ok(session);
296 }
297
298 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
299 return Err(Error::AuthError {
300 status: res_status,
301 message: error.message,
302 });
303 }
304
305 Err(Error::AuthError {
307 status: res_status,
308 message: res_body,
309 })
310 }
311
312 pub async fn login_anonymously(
329 &self,
330 options: Option<LoginAnonymouslyOptions>,
331 ) -> Result<Session, Error> {
332 let payload = LoginAnonymouslyPayload { options };
333
334 let mut headers = header::HeaderMap::new();
335 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
336 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
337
338 let body = serde_json::to_string(&payload)?;
339
340 let response = self
341 .client
342 .post(format!("{}{}/signup", self.project_url, AUTH_V1))
343 .headers(headers)
344 .body(body)
345 .send()
346 .await?;
347
348 let res_status = response.status();
349 let res_body = response.text().await?;
350
351 if let Ok(session) = from_str(&res_body) {
352 return Ok(session);
353 }
354
355 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
356 return Err(Error::AuthError {
357 status: res_status,
358 message: error.message,
359 });
360 }
361
362 Err(Error::AuthError {
364 status: res_status,
365 message: res_body,
366 })
367 }
368
369 pub async fn send_login_email_with_magic_link(&self, email: &str) -> Result<(), Error> {
378 let payload = RequestMagicLinkPayload { email };
379
380 let mut headers = header::HeaderMap::new();
381 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
382 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
383
384 let body = serde_json::to_string(&payload)?;
385
386 let response = self
387 .client
388 .post(format!("{}{}/magiclink", self.project_url, AUTH_V1))
389 .headers(headers)
390 .body(body)
391 .send()
392 .await?;
393
394 let res_status = response.status();
395 let res_body = response.text().await?;
396
397 if res_status.is_success() {
398 Ok(())
399 } else {
400 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
401 return Err(AuthError {
402 status: res_status,
403 message: error.message,
404 });
405 }
406
407 return Err(AuthError {
409 status: res_status,
410 message: res_body,
411 });
412 }
413 }
414
415 pub async fn send_sms_with_otp(&self, phone: &str) -> Result<OTPResponse, Error> {
422 let payload = SendSMSOtpPayload { phone };
423
424 let mut headers = header::HeaderMap::new();
425 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
426 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
427
428 let body = serde_json::to_string(&payload)?;
429
430 let response = self
431 .client
432 .post(format!("{}{}/otp", self.project_url, AUTH_V1))
433 .headers(headers)
434 .body(body)
435 .send()
436 .await?;
437
438 let res_status = response.status();
439 let res_body = response.text().await?;
440
441 if res_status.is_success() {
442 let message = serde_json::from_str(&res_body)?;
443 Ok(message)
444 } else {
445 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
446 return Err(AuthError {
447 status: res_status,
448 message: error.message,
449 });
450 }
451
452 return Err(AuthError {
454 status: res_status,
455 message: res_body,
456 });
457 }
458 }
459
460 pub async fn send_email_with_otp(
468 &self,
469 email: &str,
470 options: Option<LoginEmailOtpParams>,
471 ) -> Result<OTPResponse, Error> {
472 let payload = LoginWithEmailOtpPayload { email, options };
473
474 let mut headers = header::HeaderMap::new();
475 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
476 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
477
478 let body = serde_json::to_string(&payload)?;
479
480 let response = self
481 .client
482 .post(format!("{}{}/otp", self.project_url, AUTH_V1))
483 .headers(headers)
484 .body(body)
485 .send()
486 .await?;
487
488 let res_status = response.status();
489 let res_body = response.text().await?;
490
491 if res_status.is_success() {
492 let message = serde_json::from_str(&res_body)?;
493 Ok(message)
494 } else {
495 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
496 return Err(AuthError {
497 status: res_status,
498 message: error.message,
499 });
500 }
501
502 return Err(AuthError {
504 status: res_status,
505 message: res_body,
506 });
507 }
508 }
509
510 pub fn login_with_oauth(
529 &self,
530 provider: Provider,
531 options: Option<LoginWithOAuthOptions>,
532 ) -> Result<OAuthResponse, Error> {
533 let query_params = options.as_ref().map_or_else(
534 || vec![("provider", provider.to_string())],
535 |o| {
536 let mut params = vec![("provider", provider.to_string())];
537
538 if let Some(ref redirect) = o.redirect_to {
539 params.push(("redirect_to", redirect.to_string()));
540 }
541
542 if let Some(ref extra) = o.query_params {
543 params.extend(extra.iter().map(|(k, v)| (k.as_str(), v.to_string())));
544 }
545
546 params
547 },
548 );
549
550 let url = Url::parse_with_params(
551 format!("{}{}/authorize", self.project_url, AUTH_V1).as_str(),
552 query_params,
553 )
554 .map_err(|_| Error::ParseUrlError)?;
555
556 Ok(OAuthResponse { url, provider })
557 }
558
559 pub fn sign_up_with_oauth(
578 &self,
579 provider: Provider,
580 options: Option<LoginWithOAuthOptions>,
581 ) -> Result<OAuthResponse, Error> {
582 self.login_with_oauth(provider, options)
583 }
584
585 pub async fn get_user(&self, bearer_token: &str) -> Result<User, Error> {
596 let mut headers = header::HeaderMap::new();
597 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
598 headers.insert(
599 AUTHORIZATION,
600 HeaderValue::from_str(&format!("Bearer {}", bearer_token))?,
601 );
602
603 let response = self
604 .client
605 .get(format!("{}{}/user", self.project_url, AUTH_V1))
606 .headers(headers)
607 .send()
608 .await?;
609
610 let res_status = response.status();
611 let res_body = response.text().await?;
612
613 if let Ok(user) = from_str(&res_body) {
614 return Ok(user);
615 }
616
617 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
618 return Err(Error::AuthError {
619 status: res_status,
620 message: error.message,
621 });
622 }
623
624 Err(Error::AuthError {
626 status: res_status,
627 message: res_body,
628 })
629 }
630
631 pub async fn update_user(
646 &self,
647 updated_user: UpdatedUser,
648 bearer_token: &str,
649 ) -> Result<User, Error> {
650 let mut headers = header::HeaderMap::new();
651 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
652 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
653 headers.insert(
654 AUTHORIZATION,
655 HeaderValue::from_str(&format!("Bearer {}", bearer_token))?,
656 );
657
658 let body = serde_json::to_string::<UpdatedUser>(&updated_user)?;
659
660 let response = self
661 .client
662 .put(format!("{}{}/user", self.project_url, AUTH_V1))
663 .headers(headers)
664 .body(body)
665 .send()
666 .await?;
667
668 let res_status = response.status();
669 let res_body = response.text().await?;
670
671 if let Ok(user) = from_str(&res_body) {
672 return Ok(user);
673 }
674
675 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
676 return Err(Error::AuthError {
677 status: res_status,
678 message: error.message,
679 });
680 }
681
682 Err(Error::AuthError {
684 status: res_status,
685 message: res_body,
686 })
687 }
688
689 pub async fn login_with_id_token(
703 &self,
704 credentials: IdTokenCredentials,
705 ) -> Result<Session, Error> {
706 let mut headers = HeaderMap::new();
707 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
708 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
709
710 let body = serde_json::to_string(&credentials)?;
711
712 let response = self
713 .client
714 .post(format!(
715 "{}{}/token?grant_type=id_token",
716 self.project_url, AUTH_V1
717 ))
718 .headers(headers)
719 .body(body)
720 .send()
721 .await?;
722
723 let res_status = response.status();
724 let res_body = response.text().await?;
725
726 if let Ok(session) = from_str(&res_body) {
727 return Ok(session);
728 }
729
730 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
731 return Err(Error::AuthError {
732 status: res_status,
733 message: error.message,
734 });
735 }
736
737 Err(Error::AuthError {
739 status: res_status,
740 message: res_body,
741 })
742 }
743
744 pub async fn invite_user_by_email(
758 &self,
759 email: &str,
760 data: Option<Value>,
761 bearer_token: &str,
762 ) -> Result<User, Error> {
763 let mut headers = HeaderMap::new();
764 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
765 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
766 headers.insert(
767 AUTHORIZATION,
768 HeaderValue::from_str(&format!("Bearer {}", bearer_token))?,
769 );
770
771 let invite_payload = InviteParams {
772 email: email.into(),
773 data,
774 };
775
776 let body = serde_json::to_string(&invite_payload)?;
777
778 let response = self
779 .client
780 .post(format!("{}{}/invite", self.project_url, AUTH_V1))
781 .headers(headers)
782 .body(body)
783 .send()
784 .await?;
785
786 let res_status = response.status();
787 let res_body = response.text().await?;
788
789 if let Ok(user) = from_str(&res_body) {
790 return Ok(user);
791 }
792
793 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
794 return Err(Error::AuthError {
795 status: res_status,
796 message: error.message,
797 });
798 }
799
800 Err(Error::AuthError {
802 status: res_status,
803 message: res_body,
804 })
805 }
806
807 pub async fn verify_otp(&self, params: VerifyOtpParams) -> Result<Session, Error> {
822 let mut headers = HeaderMap::new();
823 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
824 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
825
826 let body = serde_json::to_string(¶ms)?;
827
828 let response = self
829 .client
830 .post(&format!("{}{}/verify", self.project_url, AUTH_V1))
831 .headers(headers)
832 .body(body)
833 .send()
834 .await?;
835
836 let res_status = response.status();
837 let res_body = response.text().await?;
838
839 if let Ok(session) = from_str(&res_body) {
840 return Ok(session);
841 }
842
843 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
844 return Err(Error::AuthError {
845 status: res_status,
846 message: error.message,
847 });
848 }
849
850 Err(Error::AuthError {
852 status: res_status,
853 message: res_body,
854 })
855 }
856
857 pub async fn get_health(&self) -> Result<AuthServerHealth, Error> {
866 let mut headers = HeaderMap::new();
867 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
868
869 let response = self
870 .client
871 .get(&format!("{}{}/health", self.project_url, AUTH_V1))
872 .headers(headers)
873 .send()
874 .await?;
875
876 let res_status = response.status();
877 let res_body = response.text().await?;
878
879 if let Ok(health) = from_str::<AuthServerHealth>(&res_body) {
880 return Ok(health);
881 }
882
883 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
884 return Err(Error::AuthError {
885 status: res_status,
886 message: error.message,
887 });
888 }
889
890 Err(Error::AuthError {
892 status: res_status,
893 message: res_body,
894 })
895 }
896
897 pub async fn get_settings(&self) -> Result<AuthServerSettings, Error> {
906 let mut headers = HeaderMap::new();
907 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
908
909 let response = self
910 .client
911 .get(&format!("{}{}/settings", self.project_url, AUTH_V1))
912 .headers(headers)
913 .send()
914 .await?;
915
916 let res_status = response.status();
917 let res_body = response.text().await?;
918
919 if let Ok(settings) = from_str(&res_body) {
920 return Ok(settings);
921 }
922
923 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
924 return Err(Error::AuthError {
925 status: res_status,
926 message: error.message,
927 });
928 }
929
930 Err(Error::AuthError {
932 status: res_status,
933 message: res_body,
934 })
935 }
936
937 pub async fn exchange_token_for_session(&self, refresh_token: &str) -> Result<Session, Error> {
953 let mut headers = HeaderMap::new();
954 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
955 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
956
957 let body = serde_json::to_string(&RefreshSessionPayload { refresh_token })?;
958
959 let response = self
960 .client
961 .post(&format!(
962 "{}{}/token?grant_type=refresh_token",
963 self.project_url, AUTH_V1
964 ))
965 .headers(headers)
966 .body(body)
967 .send()
968 .await?;
969
970 let res_status = response.status();
971 let res_body = response.text().await?;
972
973 if let Ok(session) = from_str(&res_body) {
974 return Ok(session);
975 }
976
977 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
978 return Err(Error::AuthError {
979 status: res_status,
980 message: error.message,
981 });
982 }
983
984 Err(Error::AuthError {
986 status: res_status,
987 message: res_body,
988 })
989 }
990
991 pub async fn refresh_session(&self, refresh_token: &str) -> Result<Session, Error> {
992 self.exchange_token_for_session(refresh_token).await
993 }
994
995 pub async fn exchange_code_for_session(
1028 &self,
1029 auth_code: &str,
1030 code_verifier: &str,
1031 ) -> Result<Session, Error> {
1032 let mut headers = HeaderMap::new();
1033 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
1034 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
1035
1036 let body = serde_json::to_string(&ExchangeCodeForSessionPayload {
1037 auth_code,
1038 code_verifier,
1039 })?;
1040
1041 let response = self
1042 .client
1043 .post(&format!(
1044 "{}{}/token?grant_type=pkce",
1045 self.project_url, AUTH_V1
1046 ))
1047 .headers(headers)
1048 .body(body)
1049 .send()
1050 .await?;
1051
1052 let res_status = response.status();
1053 let res_body = response.text().await?;
1054
1055 if let Ok(session) = from_str(&res_body) {
1056 return Ok(session);
1057 }
1058
1059 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
1060 return Err(Error::AuthError {
1061 status: res_status,
1062 message: error.message,
1063 });
1064 }
1065
1066 Err(Error::AuthError {
1068 status: res_status,
1069 message: res_body,
1070 })
1071 }
1072
1073 pub async fn reset_password_for_email(
1080 &self,
1081 email: &str,
1082 options: Option<ResetPasswordOptions>,
1083 ) -> Result<(), Error> {
1084 let redirect_to = options
1085 .as_ref()
1086 .and_then(|o| o.email_redirect_to.as_deref().map(str::to_owned));
1087
1088 let payload = ResetPasswordForEmailPayload {
1089 email: String::from(email),
1090 options,
1091 };
1092
1093 let mut headers = HeaderMap::new();
1094 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
1095 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
1096
1097 let body = serde_json::to_string(&payload)?;
1098
1099 let response = self
1100 .client
1101 .post(&format!("{}{}/recover", self.project_url, AUTH_V1))
1102 .query(&[("redirect_to", redirect_to.as_deref())])
1103 .headers(headers)
1104 .body(body)
1105 .send()
1106 .await?;
1107
1108 let res_status = response.status();
1109 let res_body = response.text().await?;
1110
1111 if res_status.is_success() {
1112 return Ok(());
1113 }
1114
1115 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
1116 return Err(Error::AuthError {
1117 status: res_status,
1118 message: error.message,
1119 });
1120 }
1121
1122 Err(Error::AuthError {
1123 status: res_status,
1124 message: res_body,
1125 })
1126 }
1127
1128 pub async fn resend(&self, credentials: ResendParams) -> Result<(), Error> {
1141 let mut headers = HeaderMap::new();
1142 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
1143 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
1144
1145 let body = serde_json::to_string(&credentials)?;
1146
1147 let response = self
1148 .client
1149 .post(&format!("{}{}/resend", self.project_url, AUTH_V1))
1150 .headers(headers)
1151 .body(body)
1152 .send()
1153 .await?;
1154
1155 let res_status = response.status();
1156 let res_body = response.text().await?;
1157
1158 if res_status.is_success() {
1159 return Ok(());
1160 }
1161
1162 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
1163 return Err(Error::AuthError {
1164 status: res_status,
1165 message: error.message,
1166 });
1167 }
1168
1169 Err(Error::AuthError {
1170 status: res_status,
1171 message: res_body,
1172 })
1173 }
1174
1175 pub async fn logout(
1181 &self,
1182 scope: Option<LogoutScope>,
1183 bearer_token: &str,
1184 ) -> Result<(), Error> {
1185 let mut headers = HeaderMap::new();
1186 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
1187 headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
1188 headers.insert(
1189 AUTHORIZATION,
1190 HeaderValue::from_str(&format!("Bearer {}", bearer_token))?,
1191 );
1192
1193 let body = serde_json::to_string(&scope)?;
1194
1195 let response = self
1196 .client
1197 .post(&format!("{}{}/logout", self.project_url, AUTH_V1))
1198 .headers(headers)
1199 .body(body)
1200 .send()
1201 .await?;
1202
1203 let res_status = response.status();
1204 let res_body = response.text().await?;
1205
1206 if res_status.is_success() {
1207 return Ok(());
1208 }
1209
1210 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
1211 return Err(Error::AuthError {
1212 status: res_status,
1213 message: error.message,
1214 });
1215 }
1216
1217 Err(Error::AuthError {
1218 status: res_status,
1219 message: res_body,
1220 })
1221 }
1222
1223 pub async fn sso(&self, params: LoginWithSSO) -> Result<Url, Error> {
1235 let mut headers = HeaderMap::new();
1236 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
1237 headers.insert("apikey", HeaderValue::from_str(&self.api_key)?);
1238
1239 let body = serde_json::to_string::<crate::models::LoginWithSSO>(¶ms)?;
1240
1241 let response = self
1242 .client
1243 .post(&format!("{}{}/sso", self.project_url, AUTH_V1))
1244 .headers(headers)
1245 .body(body)
1246 .send()
1247 .await?;
1248
1249 let res_status = response.status();
1250 let url = response.url().clone();
1251 let res_body = response.text().await?;
1252
1253 if res_status.is_server_error() || res_status.is_client_error() {
1254 if let Ok(error) = from_str::<SupabaseHTTPError>(&res_body) {
1255 return Err(AuthError {
1256 status: res_status,
1257 message: error.message,
1258 });
1259 }
1260
1261 return Err(AuthError {
1263 status: res_status,
1264 message: res_body,
1265 });
1266 }
1267
1268 Ok(url)
1269 }
1270
1271 pub fn project_url(&self) -> &str {
1273 &self.project_url
1274 }
1275
1276 pub fn api_key(&self) -> &str {
1278 &self.api_key
1279 }
1280
1281 pub fn jwt_secret(&self) -> &str {
1283 &self.jwt_secret
1284 }
1285}