firebase_auth_sdk/api/
user.rs

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// User Info
127#[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    // kind: String,
137    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// Change Email/Password
156#[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// Provider User Info
185#[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// Email Verification
195#[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}