1use super::FailResponse;
2use crate::error::Error;
3use serde::{Deserialize, Serialize};
4
5impl crate::FireAuth {
6 pub async fn get_user_info(&self, id_token: &str) -> Result<User, Error> {
7 let url = format!(
8 "https://identitytoolkit.googleapis.com/v1/accounts:lookup?key={}",
9 self.api_key,
10 );
11
12 let client = reqwest::Client::new();
13 let resp = client
14 .post(url)
15 .header("Content-Type", "application/json")
16 .json(&UserInfoPayload { id_token })
17 .send()
18 .await?;
19
20 if resp.status() != 200 {
21 let error = resp.json::<FailResponse>().await?.error;
22 return Err(Error::User(error.message));
23 }
24
25 let body = resp.json::<UserInfoResponse>().await?;
26 Ok(body.users[0].clone())
27 }
28
29 pub async fn change_email(
30 &self,
31 id_token: &str,
32 email: &str,
33 return_secure_token: bool,
34 ) -> Result<UpdateUser, Error> {
35 self.update_user(id_token, Some(email), None, return_secure_token)
36 .await
37 }
38
39 pub async fn change_password(
40 &self,
41 id_token: &str,
42 password: &str,
43 return_secure_token: bool,
44 ) -> Result<UpdateUser, Error> {
45 self.update_user(id_token, None, Some(password), return_secure_token)
46 .await
47 }
48
49 pub async fn reset_password(&self, email: &str) -> Result<SendOobCode, Error> {
50 self.send_oob_code("PASSWORD_RESET", None, Some(email))
51 .await
52 }
53
54 pub async fn verify_email(&self, id_token: &str) -> Result<SendOobCode, Error> {
55 self.send_oob_code("VERIFY_EMAIL", Some(id_token), None)
56 .await
57 }
58
59 async fn update_user(
60 &self,
61 id_token: &str,
62 email: Option<&str>,
63 password: Option<&str>,
64 return_secure_token: bool,
65 ) -> Result<UpdateUser, Error> {
66 let url = format!(
67 "https://identitytoolkit.googleapis.com/v1/accounts:update?key={}",
68 self.api_key,
69 );
70
71 let client = reqwest::Client::new();
72 let resp = client
73 .post(url)
74 .header("Content-Type", "application/json")
75 .json(&UpdateUserPayload {
76 id_token,
77 email,
78 password,
79 return_secure_token,
80 })
81 .send()
82 .await?;
83
84 if resp.status() != 200 {
85 let error = resp.json::<FailResponse>().await?.error;
86 return Err(Error::User(error.message));
87 }
88
89 let body = resp.json::<UpdateUser>().await?;
90 Ok(body)
91 }
92
93 async fn send_oob_code(
94 &self,
95 request_type: &str,
96 id_token: Option<&str>,
97 email: Option<&str>,
98 ) -> Result<SendOobCode, Error> {
99 let url = format!(
100 "https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key={}",
101 self.api_key,
102 );
103
104 let client = reqwest::Client::new();
105 let resp = client
106 .post(url)
107 .header("Content-Type", "application/json")
108 .json(&SendOobCodePayload {
109 request_type,
110 id_token,
111 email,
112 })
113 .send()
114 .await?;
115
116 if resp.status() != 200 {
117 let error = resp.json::<FailResponse>().await?.error;
118 return Err(Error::User(error.message));
119 }
120
121 let body = resp.json::<SendOobCode>().await?;
122 Ok(body)
123 }
124}
125
126#[derive(Debug, Serialize)]
128#[serde(rename_all = "camelCase")]
129struct UserInfoPayload<'a> {
130 id_token: &'a str,
131}
132
133#[derive(Debug, Deserialize)]
134#[serde(rename_all = "camelCase")]
135struct UserInfoResponse {
136 users: Vec<User>,
138}
139
140#[derive(Clone, Debug, Serialize, Deserialize)]
141#[serde(rename_all = "camelCase")]
142pub struct User {
143 pub local_id: String,
144 pub email: String,
145 pub password_hash: String,
146 pub email_verified: bool,
147 pub password_updated_at: u64,
148 pub provider_user_info: Vec<ProviderUserInfo>,
149 pub valid_since: String,
150 pub last_login_at: String,
151 pub created_at: String,
152 pub last_refresh_at: String,
153}
154
155#[derive(Debug, Serialize)]
157#[serde(rename_all = "camelCase")]
158struct UpdateUserPayload<'a> {
159 id_token: &'a str,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
162 email: Option<&'a str>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
165 password: Option<&'a str>,
166
167 return_secure_token: bool,
168}
169
170#[derive(Debug, Serialize, Deserialize)]
171#[serde(rename_all = "camelCase")]
172pub struct UpdateUser {
173 pub kind: String,
174 pub local_id: String,
175 pub email: String,
176 pub provider_user_info: Vec<ProviderUserInfo>,
177 pub password_hash: String,
178 pub email_verified: bool,
179 pub id_token: Option<String>,
180 pub refresh_token: Option<String>,
181 pub expires_in: Option<String>,
182}
183
184#[derive(Clone, Debug, Serialize, Deserialize)]
186#[serde(rename_all = "camelCase")]
187pub struct ProviderUserInfo {
188 pub provider_id: String,
189 pub federated_id: String,
190 pub email: String,
191 pub raw_id: String,
192}
193
194#[derive(Debug, Serialize)]
196#[serde(rename_all = "camelCase")]
197struct SendOobCodePayload<'a> {
198 request_type: &'a str,
199 id_token: Option<&'a str>,
200 email: Option<&'a str>,
201}
202
203#[derive(Debug, Serialize, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct SendOobCode {
206 pub kind: String,
207 pub email: String,
208}