1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//! The error types for APIs.
use serde::Deserialize;
use std::fmt::{Display, Formatter};
/// The error type for APIs.
#[derive(Debug, thiserror::Error)]
pub enum Error {
// HTTP client errors
/// Invalid header value.
#[error("Invalid header value: {key:?} - {error:?}")]
InvalidHeaderValue {
key: &'static str,
error: reqwest::header::InvalidHeaderValue,
},
/// HTTP request error.
#[error("HTTP request error: {0:?}")]
HttpRequestError(reqwest::Error),
// API errors
/// API error on the Firebase Auth.
#[error(
"Firebase Auth API error: ({status_code:?}) {error_code:?} - {response:?}"
)]
ApiError {
status_code: reqwest::StatusCode,
error_code: CommonErrorCode,
response: ApiErrorResponse,
},
/// Invalid ID token error.
#[error("Invalid ID token")]
InvalidIdToken,
// Response errors
/// Read response text failed.
#[error("Read response text failed: {error:?}")]
ReadResponseTextFailed {
error: reqwest::Error,
},
/// Deserialize response JSON failed.
#[error("Deserialize response JSON failed: {error:?} - {json:?}")]
DeserializeResponseJsonFailed {
error: serde_json::Error,
json: String,
},
/// Deserialize error response JSON failed.
#[error("Deserialize error response JSON failed: {error:?} - {json:?}")]
DeserializeErrorResponseJsonFailed {
error: serde_json::Error,
json: String,
},
/// Parse `expires_in` failed.
#[error("Parse expires_in failed: {error:?}")]
ParseExpriesInFailed {
error: std::num::ParseIntError,
},
/// Not found any user data in a response.
#[error("Not found any user data in a response")]
NotFoundAnyUserData,
}
/// Error response payload for the auth endpoints.
///
/// See also [API reference](https://firebase.google.com/docs/reference/rest/auth#section-error-response).
#[derive(Debug, Deserialize)]
pub struct ApiErrorResponse {
#[serde(rename = "error")]
pub error: ErrorResponse,
}
impl Display for ApiErrorResponse {
fn fmt(
&self,
f: &mut Formatter<'_>,
) -> std::fmt::Result {
write!(f, "{:?}", self.error)
}
}
/// Error response payload for the auth endpoints.
///
/// See also [API reference](https://firebase.google.com/docs/reference/rest/auth#section-error-response).
#[derive(Debug, Deserialize)]
pub struct ErrorResponse {
#[serde(rename = "errors")]
pub errors: Vec<ErrorElement>,
#[serde(rename = "code")]
pub code: i64,
#[serde(rename = "message")]
pub message: String,
}
/// Error response payload for the auth endpoints.
///
/// See also [API reference](https://firebase.google.com/docs/reference/rest/auth#section-error-response).
#[derive(Debug, Deserialize)]
pub struct ErrorElement {
#[serde(rename = "domain")]
pub domain: String,
#[serde(rename = "reason")]
pub reason: String,
#[serde(rename = "message")]
pub message: String,
}
/// Common error codes for the Firebase Auth API.
#[derive(Debug)]
pub enum CommonErrorCode {
/// OPERATION_NOT_ALLOWED: The operation is disabled for this project.
OperationNotAllowed(String),
/// TOO_MANY_ATTEMPTS_TRY_LATER: We have blocked all requests from this device due to unusual activity. Try again later.
TooManyAttemptsTryLater,
/// INVALID_API_KEY: API key not valid. Please pass a valid API key. (invalid API key provided)
InvalidApiKey,
/// INVALID_CUSTOM_TOKEN: The custom token format is incorrect or the token is invalid for some reason (e.g. expired, invalid signature etc.)
InvalidCustomToken,
/// INVALID_ID_TOKEN:The user's credential is no longer valid. The user must sign in again.
InvalidIdToken,
/// INVALID_REFRESH_TOKEN: An invalid refresh token is provided.
InvalidRefreshToken,
/// Invalid JSON payload received. Unknown name \"refresh_tokens\": Cannot bind query parameter. Field 'refresh_tokens' could not be found in request message.
InvalidJsonPayloadReceived(String),
/// INVALID_GRANT_TYPE: the grant type specified is invalid.
InvalidGrantType,
/// INVALID_PASSWORD: The password is invalid or the user does not have a password.
InvalidPassword,
/// INVALID_IDP_RESPONSE: The supplied auth credential is malformed or has expired.
InvalidIdpResponse,
/// INVALID_EMAIL: The email address is badly formatted.
InvalidEmail,
/// INVALID_LOGIN_CREDENTIALS: The supplied auth credential is malformed or has expired.
InvalidLoginCredentials,
/// CREDENTIAL_MISMATCH: The custom token corresponds to a different Firebase project.
CredentialMismatch,
/// CREDENTIAL_TOO_OLD_LOGIN_AGAIN: The user's credential is no longer valid. The user must sign in again.
CredentialTooOldLoginAgain,
/// TOKEN_EXPIRED: The user's credential is no longer valid. The user must sign in again.
TokenExpired,
/// USER_DISABLED: The user account has been disabled by an administrator.
UserDisabled,
/// USER_NOT_FOUND: The user corresponding to the refresh token was not found. It is likely the user was deleted.
UserNotFound,
/// MISSING_REFRESH_TOKEN: no refresh token provided.
MissingRefreshToken,
/// EMAIL_EXISTS: The email address is already in use by another account.
EmailExists,
/// EMAIL_NOT_FOUND: There is no user record corresponding to this identifier. The user may have been deleted.
EmailNotFound,
/// WEAK_PASSWORD: The password must be 6 characters long or more.
WeakPassword,
/// FEDERATED_USER_ID_ALREADY_LINKED: This credential is already associated with a different user account.
FederatedUserIdAlreadyLinked,
/// EXPIRED_OOB_CODE: The action code has expired.
ExpiredOobCode,
/// INVALID_OOB_CODE: The action code is invalid. This can happen if the code is malformed, expired, or has already been used.
InvalidOobCode,
// ADMIN_ONLY_OPERATION: This operation is reserved to administrators only.
AdminOnlyOperation,
/// Unknown error codes.
Unknown(String),
}
impl From<String> for CommonErrorCode {
fn from(val: String) -> Self {
if val
.as_str()
.starts_with("Invalid JSON payload received. Unknown name")
{
return CommonErrorCode::InvalidJsonPayloadReceived(val);
}
if val
.as_str()
.starts_with("OPERATION_NOT_ALLOWED")
{
return CommonErrorCode::OperationNotAllowed(val);
}
match val.as_str() {
| "TOO_MANY_ATTEMPTS_TRY_LATER" => {
CommonErrorCode::TooManyAttemptsTryLater
},
| "INVALID_API_KEY" => CommonErrorCode::InvalidApiKey,
| "INVALID_CUSTOM_TOKEN" => CommonErrorCode::InvalidCustomToken,
| "INVALID_ID_TOKEN" => CommonErrorCode::InvalidIdToken,
| "INVALID_REFRESH_TOKEN" => CommonErrorCode::InvalidRefreshToken,
| "INVALID_GRANT_TYPE" => CommonErrorCode::InvalidGrantType,
| "INVALID_PASSWORD" => CommonErrorCode::InvalidPassword,
| "INVALID_IDP_RESPONSE" => CommonErrorCode::InvalidIdpResponse,
| "INVALID_EMAIL" => CommonErrorCode::InvalidEmail,
| "INVALID_LOGIN_CREDENTIALS" => {
CommonErrorCode::InvalidLoginCredentials
},
| "CREDENTIAL_MISMATCH" => CommonErrorCode::CredentialMismatch,
| "CREDENTIAL_TOO_OLD_LOGIN_AGAIN" => {
CommonErrorCode::CredentialTooOldLoginAgain
},
| "TOKEN_EXPIRED" => CommonErrorCode::TokenExpired,
| "USER_DISABLED" => CommonErrorCode::UserDisabled,
| "USER_NOT_FOUND" => CommonErrorCode::UserNotFound,
| "MISSING_REFRESH_TOKEN" => CommonErrorCode::MissingRefreshToken,
| "EMAIL_EXISTS" => CommonErrorCode::EmailExists,
| "EMAIL_NOT_FOUND" => CommonErrorCode::EmailNotFound,
| "WEAK_PASSWORD" => CommonErrorCode::WeakPassword,
| "FEDERATED_USER_ID_ALREADY_LINKED" => {
CommonErrorCode::FederatedUserIdAlreadyLinked
},
| "EXPIRED_OOB_CODE" => CommonErrorCode::ExpiredOobCode,
| "INVALID_OOB_CODE" => CommonErrorCode::InvalidOobCode,
| "ADMIN_ONLY_OPERATION" => CommonErrorCode::AdminOnlyOperation,
| _ => CommonErrorCode::Unknown(val),
}
}
}