1use mime::Mime;
4use serde::{Deserialize, Serialize};
5use serde_enum_str::{Deserialize_enum_str, Serialize_enum_str};
6use serde_json::{Map, Value};
7use url::Url;
8
9use crate::types::{AccessTokenType, IdToken, Scope, ScopeFromStrError, ScopeParameter};
10
11pub const CONTENT_TYPE: Mime = mime::APPLICATION_JSON;
12pub const GENERAL_ERROR_BODY_KEY_ERROR: &str = "error";
13
14#[derive(Serialize, Deserialize, Debug, Clone)]
18pub struct SuccessfulBody<SCOPE>
19where
20 SCOPE: Scope,
21{
22 pub access_token: String,
23 #[serde(default)]
25 pub token_type: AccessTokenType,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub expires_in: Option<usize>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub refresh_token: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 #[serde(alias = "scopes")]
34 pub scope: Option<ScopeParameter<SCOPE>>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub id_token: Option<IdToken>,
39
40 #[serde(flatten, skip_serializing_if = "Option::is_none")]
41 pub _extra: Option<Map<String, Value>>,
42}
43impl<SCOPE> SuccessfulBody<SCOPE>
44where
45 SCOPE: Scope,
46{
47 pub fn new(
48 access_token: String,
49 token_type: AccessTokenType,
50 expires_in: Option<usize>,
51 refresh_token: Option<String>,
52 scope: Option<ScopeParameter<SCOPE>>,
53 ) -> Self {
54 Self {
55 access_token,
56 token_type,
57 expires_in,
58 refresh_token,
59 scope,
60 id_token: None,
61 _extra: None,
62 }
63 }
64
65 pub fn set_extra(&mut self, extra: Map<String, Value>) {
66 self._extra = Some(extra);
67 }
68 pub fn extra(&self) -> Option<&Map<String, Value>> {
69 self._extra.as_ref()
70 }
71
72 pub fn try_from_t_with_string(
73 body: &SuccessfulBody<String>,
74 ) -> Result<Self, ScopeFromStrError> {
75 let scope = if let Some(x) = &body.scope {
76 Some(ScopeParameter::<SCOPE>::try_from_t_with_string(x)?)
77 } else {
78 None
79 };
80
81 let mut this = Self::new(
82 body.access_token.to_owned(),
83 body.token_type.to_owned(),
84 body.expires_in.to_owned(),
85 body.refresh_token.to_owned(),
86 scope,
87 );
88 if let Some(extra) = body.extra() {
89 this.set_extra(extra.to_owned());
90 }
91 Ok(this)
92 }
93}
94
95impl<SCOPE> From<&SuccessfulBody<SCOPE>> for SuccessfulBody<String>
96where
97 SCOPE: Scope,
98{
99 fn from(body: &SuccessfulBody<SCOPE>) -> Self {
100 let mut this = Self::new(
101 body.access_token.to_owned(),
102 body.token_type.to_owned(),
103 body.expires_in.to_owned(),
104 body.refresh_token.to_owned(),
105 body.scope
106 .to_owned()
107 .map(|x| ScopeParameter::<String>::from(&x)),
108 );
109 if let Some(extra) = body.extra() {
110 this.set_extra(extra.to_owned());
111 }
112 this
113 }
114}
115
116#[derive(Serialize, Deserialize, Debug, Clone)]
120pub struct ErrorBody {
121 #[serde(default)]
123 pub error: ErrorBodyError,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub error_description: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub error_uri: Option<Url>,
128
129 #[serde(flatten, skip_serializing_if = "Option::is_none")]
130 _extra: Option<Map<String, Value>>,
131}
132impl ErrorBody {
133 pub fn new(
134 error: ErrorBodyError,
135 error_description: Option<String>,
136 error_uri: Option<Url>,
137 ) -> Self {
138 Self {
139 error,
140 error_description,
141 error_uri,
142 _extra: None,
143 }
144 }
145
146 pub fn set_extra(&mut self, extra: Map<String, Value>) {
147 self._extra = Some(extra);
148 }
149 pub fn extra(&self) -> Option<&Map<String, Value>> {
150 self._extra.as_ref()
151 }
152}
153
154#[derive(Deserialize_enum_str, Serialize_enum_str, Debug, Clone, PartialEq, Eq)]
155#[serde(rename_all = "snake_case")]
156pub enum ErrorBodyError {
157 InvalidRequest,
162 InvalidClient,
164 InvalidGrant,
166 UnauthorizedClient,
168 UnsupportedGrantType,
170 InvalidScope,
172 UnsupportedResponseType,
177 AuthorizationPending,
182 SlowDown,
184 ExpiredToken,
186 AccessDenied,
193 ServerError,
199 TemporarilyUnavailable,
202 #[serde(other)]
206 Other(String),
207}
208impl Default for ErrorBodyError {
209 fn default() -> Self {
210 Self::Other("".to_owned())
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_ser_de_error_body() {
220 let body_str = r#"
221 {
222 "error": "invalid_scope"
223 }
224 "#;
225 match serde_json::from_str::<ErrorBody>(body_str) {
226 Ok(body) => {
227 assert_eq!(body.error, ErrorBodyError::InvalidScope);
228 }
229 Err(err) => panic!("{err}"),
230 }
231 }
232}
233
234#[cfg(test)]
235mod tests_with_authorization_code_grant {
236 use super::*;
237
238 #[test]
239 fn test_ser_de_error_body() {
240 let body_str = r#"
241 {
242 "error": "authorization_pending"
243 }
244 "#;
245 match serde_json::from_str::<ErrorBody>(body_str) {
246 Ok(body) => {
247 assert_eq!(body.error, ErrorBodyError::AuthorizationPending);
248 }
249 Err(err) => panic!("{err}"),
250 }
251 }
252}