supabase_auth_redux/
signin_with_password.rs1use serde::{Deserialize, Serialize};
2use tracing::{debug, error, info, instrument, trace_span, Instrument};
3
4use crate::error::AuthError;
5use crate::models::token::TokenResponse;
6use crate::util::handle_response_code;
7use crate::AuthClient;
8use crate::IdType;
9
10#[derive(Debug, Deserialize, Serialize)]
11struct TokenPasswordGrant {
12 email: Option<String>,
13 phone: Option<String>,
14 password: String,
15}
16
17impl AuthClient {
18 #[instrument(skip_all)]
57 pub async fn signin_with_password(
58 &self,
59 id: IdType,
60 password: String,
61 ) -> Result<TokenResponse, AuthError> {
62 if password.is_empty() {
63 error!("empty password");
64 return Err(AuthError::InvalidParameters);
65 }
66
67 let token_password_grant = match id {
68 IdType::Email(email) => {
69 if email.is_empty() {
70 error!("empty email");
71 return Err(AuthError::InvalidParameters);
72 }
73
74 info!(email = email);
75 TokenPasswordGrant {
76 email: Some(email),
77 phone: None,
78 password,
79 }
80 }
81 IdType::PhoneNumber(phone_number) => {
82 if phone_number.is_empty() {
83 error!("empty phone_number");
84 return Err(AuthError::InvalidParameters);
85 }
86
87 info!(phone_number = phone_number);
88 TokenPasswordGrant {
89 email: None,
90 phone: Some(phone_number),
91 password,
92 }
93 }
94 };
95
96 let resp = match self
97 .http_client
98 .post(format!(
99 "{}/auth/v1/{}",
100 self.supabase_api_url, "token?grant_type=password"
101 ))
102 .bearer_auth(&self.supabase_anon_key)
103 .header("apiKey", &self.supabase_anon_key)
104 .json(&token_password_grant)
105 .send()
106 .instrument(trace_span!("gotrue token password"))
107 .await
108 {
109 Ok(resp) => resp,
110 Err(e) => {
111 error!("{}", e);
112 return Err(AuthError::Http);
113 }
114 };
115 let resp_code_result = handle_response_code(resp.status()).await;
116 let resp_text = match resp.text().await {
117 Ok(resp_text) => resp_text,
118 Err(e) => {
119 log::error!("{}", e);
120 return Err(AuthError::Http);
121 }
122 };
123 debug!("resp_text: {}", resp_text);
124 resp_code_result?;
125
126 let token_response = match serde_json::from_str::<TokenResponse>(&resp_text) {
127 Ok(token_response) => token_response,
128 Err(e) => {
129 error!("{}", e);
130 return Err(AuthError::Internal);
131 }
132 };
133 info!(
134 tokens_are_nonempty =
135 !token_response.access_token.is_empty() && !token_response.refresh_token.is_empty()
136 );
137 debug!(
138 token = token_response.access_token,
139 refresh_token = token_response.refresh_token
140 );
141
142 Ok(token_response)
143 }
144}