1use std::borrow::Cow;
10
11use serde::{Deserialize, Serialize};
12use serde_with::{DeserializeFromStr, SerializeDisplay};
13
14#[derive(Debug, Serialize, Deserialize, Clone)]
19pub struct ClientError {
20    pub error: ClientErrorCode,
22
23    #[serde(skip_serializing_if = "Option::is_none")]
25    pub error_description: Option<Cow<'static, str>>,
26}
27
28impl ClientError {
29    #[must_use]
31    pub const fn new(error: ClientErrorCode, error_description: &'static str) -> Self {
32        Self {
33            error,
34            error_description: Some(Cow::Borrowed(error_description)),
35        }
36    }
37
38    #[must_use]
40    pub fn with_description(mut self, description: String) -> Self {
41        self.error_description = Some(Cow::Owned(description));
42        self
43    }
44}
45
46impl From<ClientErrorCode> for ClientError {
47    fn from(error: ClientErrorCode) -> Self {
48        let desc = error.default_description();
49        Self::new(error, desc)
50    }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr)]
55pub enum ClientErrorCode {
56    InvalidRequest,
64
65    InvalidClient,
72
73    InvalidGrant,
82
83    UnauthorizedClient,
90
91    UnsupportedGrantType,
98
99    AccessDenied,
105
106    UnsupportedResponseType,
113
114    InvalidScope,
121
122    ServerError,
129
130    TemporarilyUnavailable,
137
138    InteractionRequired,
145
146    LoginRequired,
152
153    AccountSelectionRequired,
160
161    ConsentRequired,
167
168    InvalidRequestUri,
175
176    InvalidRequestObject,
182
183    RequestNotSupported,
190
191    RequestUriNotSupported,
198
199    RegistrationNotSupported,
206
207    InvalidRedirectUri,
213
214    InvalidClientMetadata,
221
222    AuthorizationPending,
236
237    SlowDown,
246
247    ExpiredToken,
258
259    UnsupportedTokenType,
267
268    Unknown(String),
270}
271
272impl core::fmt::Display for ClientErrorCode {
273    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
274        match self {
275            ClientErrorCode::InvalidRequest => f.write_str("invalid_request"),
276            ClientErrorCode::InvalidClient => f.write_str("invalid_client"),
277            ClientErrorCode::InvalidGrant => f.write_str("invalid_grant"),
278            ClientErrorCode::UnauthorizedClient => f.write_str("unauthorized_client"),
279            ClientErrorCode::UnsupportedGrantType => f.write_str("unsupported_grant_type"),
280            ClientErrorCode::AccessDenied => f.write_str("access_denied"),
281            ClientErrorCode::UnsupportedResponseType => f.write_str("unsupported_response_type"),
282            ClientErrorCode::InvalidScope => f.write_str("invalid_scope"),
283            ClientErrorCode::ServerError => f.write_str("server_error"),
284            ClientErrorCode::TemporarilyUnavailable => f.write_str("temporarily_unavailable"),
285            ClientErrorCode::InteractionRequired => f.write_str("interaction_required"),
286            ClientErrorCode::LoginRequired => f.write_str("login_required"),
287            ClientErrorCode::AccountSelectionRequired => f.write_str("account_selection_required"),
288            ClientErrorCode::ConsentRequired => f.write_str("consent_required"),
289            ClientErrorCode::InvalidRequestUri => f.write_str("invalid_request_uri"),
290            ClientErrorCode::InvalidRequestObject => f.write_str("invalid_request_object"),
291            ClientErrorCode::RequestNotSupported => f.write_str("request_not_supported"),
292            ClientErrorCode::RequestUriNotSupported => f.write_str("request_uri_not_supported"),
293            ClientErrorCode::RegistrationNotSupported => f.write_str("registration_not_supported"),
294            ClientErrorCode::InvalidRedirectUri => f.write_str("invalid_redirect_uri"),
295            ClientErrorCode::InvalidClientMetadata => f.write_str("invalid_client_metadata"),
296            ClientErrorCode::AuthorizationPending => f.write_str("authorization_pending"),
297            ClientErrorCode::SlowDown => f.write_str("slow_down"),
298            ClientErrorCode::ExpiredToken => f.write_str("expired_token"),
299            ClientErrorCode::UnsupportedTokenType => f.write_str("unsupported_token_type"),
300            ClientErrorCode::Unknown(value) => f.write_str(value),
301        }
302    }
303}
304
305impl core::str::FromStr for ClientErrorCode {
306    type Err = core::convert::Infallible;
307
308    fn from_str(s: &str) -> Result<Self, Self::Err> {
309        match s {
310            "invalid_request" => Ok(ClientErrorCode::InvalidRequest),
311            "invalid_client" => Ok(ClientErrorCode::InvalidClient),
312            "invalid_grant" => Ok(ClientErrorCode::InvalidGrant),
313            "unauthorized_client" => Ok(ClientErrorCode::UnauthorizedClient),
314            "unsupported_grant_type" => Ok(ClientErrorCode::UnsupportedGrantType),
315            "access_denied" => Ok(ClientErrorCode::AccessDenied),
316            "unsupported_response_type" => Ok(ClientErrorCode::UnsupportedResponseType),
317            "invalid_scope" => Ok(ClientErrorCode::InvalidScope),
318            "server_error" => Ok(ClientErrorCode::ServerError),
319            "temporarily_unavailable" => Ok(ClientErrorCode::TemporarilyUnavailable),
320            "interaction_required" => Ok(ClientErrorCode::InteractionRequired),
321            "login_required" => Ok(ClientErrorCode::LoginRequired),
322            "account_selection_required" => Ok(ClientErrorCode::AccountSelectionRequired),
323            "consent_required" => Ok(ClientErrorCode::ConsentRequired),
324            "invalid_request_uri" => Ok(ClientErrorCode::InvalidRequestUri),
325            "invalid_request_object" => Ok(ClientErrorCode::InvalidRequestObject),
326            "request_not_supported" => Ok(ClientErrorCode::RequestNotSupported),
327            "request_uri_not_supported" => Ok(ClientErrorCode::RequestUriNotSupported),
328            "registration_not_supported" => Ok(ClientErrorCode::RegistrationNotSupported),
329            "invalid_redirect_uri" => Ok(ClientErrorCode::InvalidRedirectUri),
330            "invalid_client_metadata" => Ok(ClientErrorCode::InvalidClientMetadata),
331            "authorization_pending" => Ok(ClientErrorCode::AuthorizationPending),
332            "slow_down" => Ok(ClientErrorCode::SlowDown),
333            "expired_token" => Ok(ClientErrorCode::ExpiredToken),
334            "unsupported_token_type" => Ok(ClientErrorCode::UnsupportedTokenType),
335            _ => Ok(ClientErrorCode::Unknown(s.to_owned())),
336        }
337    }
338}
339
340impl ClientErrorCode {
341    #[must_use]
345    pub fn default_description(&self) -> &'static str {
346        match self {
347            ClientErrorCode::InvalidRequest => {
348                "The request is missing a required parameter, includes an \
349                invalid parameter value, includes a parameter more than once, \
350                or is otherwise malformed."
351            }
352            ClientErrorCode::InvalidClient => "Client authentication failed.",
353            ClientErrorCode::InvalidGrant => {
354                "The provided access grant is invalid, expired, or revoked."
355            }
356            ClientErrorCode::UnauthorizedClient => {
357                "The client is not authorized to request an access token using this method."
358            }
359            ClientErrorCode::UnsupportedGrantType => {
360                "The authorization grant type is not supported by the authorization server."
361            }
362            ClientErrorCode::AccessDenied => {
363                "The resource owner or authorization server denied the request."
364            }
365            ClientErrorCode::UnsupportedResponseType => {
366                "The authorization server does not support obtaining an access \
367                token using this method."
368            }
369            ClientErrorCode::InvalidScope => {
370                "The requested scope is invalid, unknown, or malformed."
371            }
372            ClientErrorCode::ServerError => {
373                "The authorization server encountered an unexpected condition \
374                that prevented it from fulfilling the request."
375            }
376            ClientErrorCode::TemporarilyUnavailable => {
377                "The authorization server is currently unable to handle the request \
378                due to a temporary overloading or maintenance of the server."
379            }
380            ClientErrorCode::InteractionRequired => {
381                "The Authorization Server requires End-User interaction of some form to proceed."
382            }
383            ClientErrorCode::LoginRequired => {
384                "The Authorization Server requires End-User authentication."
385            }
386            ClientErrorCode::AccountSelectionRequired => {
387                "The End-User is required to select a session at the Authorization Server."
388            }
389            ClientErrorCode::ConsentRequired => {
390                "The Authorization Server requires End-User consent."
391            }
392            ClientErrorCode::InvalidRequestUri => {
393                "The request_uri in the Authorization Request returns an error \
394                or contains invalid data."
395            }
396            ClientErrorCode::InvalidRequestObject => {
397                "The request parameter contains an invalid Request Object."
398            }
399            ClientErrorCode::RequestNotSupported => {
400                "The provider does not support use of the request parameter."
401            }
402            ClientErrorCode::RequestUriNotSupported => {
403                "The provider does not support use of the request_uri parameter."
404            }
405            ClientErrorCode::RegistrationNotSupported => {
406                "The provider does not support use of the registration parameter."
407            }
408            ClientErrorCode::InvalidRedirectUri => {
409                "The value of one or more redirection URIs is invalid."
410            }
411            ClientErrorCode::InvalidClientMetadata => {
412                "The value of one of the client metadata fields is invalid"
413            }
414            ClientErrorCode::AuthorizationPending => "The authorization request is still pending",
415            ClientErrorCode::SlowDown => {
416                "The interval must be increased by 5 seconds for this and all subsequent requests"
417            }
418            ClientErrorCode::ExpiredToken => {
419                "The \"device_code\" has expired, and the device authorization session has concluded"
420            }
421            ClientErrorCode::UnsupportedTokenType => {
422                "The authorization server does not support the revocation of the presented token type."
423            }
424            ClientErrorCode::Unknown(_) => "",
425        }
426    }
427}
428
429#[cfg(test)]
430mod tests {
431    use super::*;
432
433    #[test]
434    fn serialize_client_error_code() {
435        assert_eq!(
436            serde_json::to_string(&ClientErrorCode::InvalidRequest).unwrap(),
437            "\"invalid_request\""
438        );
439        assert_eq!(
440            serde_json::to_string(&ClientErrorCode::InvalidClient).unwrap(),
441            "\"invalid_client\""
442        );
443        assert_eq!(
444            serde_json::to_string(&ClientErrorCode::InvalidGrant).unwrap(),
445            "\"invalid_grant\""
446        );
447        assert_eq!(
448            serde_json::to_string(&ClientErrorCode::UnauthorizedClient).unwrap(),
449            "\"unauthorized_client\""
450        );
451        assert_eq!(
452            serde_json::to_string(&ClientErrorCode::UnsupportedGrantType).unwrap(),
453            "\"unsupported_grant_type\""
454        );
455        assert_eq!(
456            serde_json::to_string(&ClientErrorCode::AccessDenied).unwrap(),
457            "\"access_denied\""
458        );
459        assert_eq!(
460            serde_json::to_string(&ClientErrorCode::UnsupportedResponseType).unwrap(),
461            "\"unsupported_response_type\""
462        );
463        assert_eq!(
464            serde_json::to_string(&ClientErrorCode::InvalidScope).unwrap(),
465            "\"invalid_scope\""
466        );
467        assert_eq!(
468            serde_json::to_string(&ClientErrorCode::ServerError).unwrap(),
469            "\"server_error\""
470        );
471        assert_eq!(
472            serde_json::to_string(&ClientErrorCode::TemporarilyUnavailable).unwrap(),
473            "\"temporarily_unavailable\""
474        );
475        assert_eq!(
476            serde_json::to_string(&ClientErrorCode::InteractionRequired).unwrap(),
477            "\"interaction_required\""
478        );
479        assert_eq!(
480            serde_json::to_string(&ClientErrorCode::LoginRequired).unwrap(),
481            "\"login_required\""
482        );
483        assert_eq!(
484            serde_json::to_string(&ClientErrorCode::AccountSelectionRequired).unwrap(),
485            "\"account_selection_required\""
486        );
487        assert_eq!(
488            serde_json::to_string(&ClientErrorCode::ConsentRequired).unwrap(),
489            "\"consent_required\""
490        );
491        assert_eq!(
492            serde_json::to_string(&ClientErrorCode::InvalidRequestUri).unwrap(),
493            "\"invalid_request_uri\""
494        );
495        assert_eq!(
496            serde_json::to_string(&ClientErrorCode::InvalidRequestObject).unwrap(),
497            "\"invalid_request_object\""
498        );
499        assert_eq!(
500            serde_json::to_string(&ClientErrorCode::RequestNotSupported).unwrap(),
501            "\"request_not_supported\""
502        );
503        assert_eq!(
504            serde_json::to_string(&ClientErrorCode::RequestUriNotSupported).unwrap(),
505            "\"request_uri_not_supported\""
506        );
507        assert_eq!(
508            serde_json::to_string(&ClientErrorCode::RegistrationNotSupported).unwrap(),
509            "\"registration_not_supported\""
510        );
511        assert_eq!(
512            serde_json::to_string(&ClientErrorCode::InvalidRedirectUri).unwrap(),
513            "\"invalid_redirect_uri\""
514        );
515        assert_eq!(
516            serde_json::to_string(&ClientErrorCode::InvalidClientMetadata).unwrap(),
517            "\"invalid_client_metadata\""
518        );
519
520        assert_eq!(
521            serde_json::to_string(&ClientErrorCode::Unknown("unknown_error_code".to_owned()))
522                .unwrap(),
523            "\"unknown_error_code\""
524        );
525    }
526
527    #[test]
528    fn deserialize_client_error_code() {
529        assert_eq!(
530            serde_json::from_str::<ClientErrorCode>("\"invalid_request\"").unwrap(),
531            ClientErrorCode::InvalidRequest
532        );
533        assert_eq!(
534            serde_json::from_str::<ClientErrorCode>("\"invalid_client\"").unwrap(),
535            ClientErrorCode::InvalidClient
536        );
537        assert_eq!(
538            serde_json::from_str::<ClientErrorCode>("\"invalid_grant\"").unwrap(),
539            ClientErrorCode::InvalidGrant
540        );
541        assert_eq!(
542            serde_json::from_str::<ClientErrorCode>("\"unauthorized_client\"").unwrap(),
543            ClientErrorCode::UnauthorizedClient
544        );
545        assert_eq!(
546            serde_json::from_str::<ClientErrorCode>("\"unsupported_grant_type\"").unwrap(),
547            ClientErrorCode::UnsupportedGrantType
548        );
549        assert_eq!(
550            serde_json::from_str::<ClientErrorCode>("\"access_denied\"").unwrap(),
551            ClientErrorCode::AccessDenied
552        );
553        assert_eq!(
554            serde_json::from_str::<ClientErrorCode>("\"unsupported_response_type\"").unwrap(),
555            ClientErrorCode::UnsupportedResponseType
556        );
557        assert_eq!(
558            serde_json::from_str::<ClientErrorCode>("\"invalid_scope\"").unwrap(),
559            ClientErrorCode::InvalidScope
560        );
561        assert_eq!(
562            serde_json::from_str::<ClientErrorCode>("\"server_error\"").unwrap(),
563            ClientErrorCode::ServerError
564        );
565        assert_eq!(
566            serde_json::from_str::<ClientErrorCode>("\"temporarily_unavailable\"").unwrap(),
567            ClientErrorCode::TemporarilyUnavailable
568        );
569        assert_eq!(
570            serde_json::from_str::<ClientErrorCode>("\"interaction_required\"").unwrap(),
571            ClientErrorCode::InteractionRequired
572        );
573        assert_eq!(
574            serde_json::from_str::<ClientErrorCode>("\"login_required\"").unwrap(),
575            ClientErrorCode::LoginRequired
576        );
577        assert_eq!(
578            serde_json::from_str::<ClientErrorCode>("\"account_selection_required\"").unwrap(),
579            ClientErrorCode::AccountSelectionRequired
580        );
581        assert_eq!(
582            serde_json::from_str::<ClientErrorCode>("\"consent_required\"").unwrap(),
583            ClientErrorCode::ConsentRequired
584        );
585        assert_eq!(
586            serde_json::from_str::<ClientErrorCode>("\"invalid_request_uri\"").unwrap(),
587            ClientErrorCode::InvalidRequestUri
588        );
589        assert_eq!(
590            serde_json::from_str::<ClientErrorCode>("\"invalid_request_object\"").unwrap(),
591            ClientErrorCode::InvalidRequestObject
592        );
593        assert_eq!(
594            serde_json::from_str::<ClientErrorCode>("\"request_not_supported\"").unwrap(),
595            ClientErrorCode::RequestNotSupported
596        );
597        assert_eq!(
598            serde_json::from_str::<ClientErrorCode>("\"request_uri_not_supported\"").unwrap(),
599            ClientErrorCode::RequestUriNotSupported
600        );
601        assert_eq!(
602            serde_json::from_str::<ClientErrorCode>("\"registration_not_supported\"").unwrap(),
603            ClientErrorCode::RegistrationNotSupported
604        );
605        assert_eq!(
606            serde_json::from_str::<ClientErrorCode>("\"invalid_redirect_uri\"").unwrap(),
607            ClientErrorCode::InvalidRedirectUri
608        );
609        assert_eq!(
610            serde_json::from_str::<ClientErrorCode>("\"invalid_client_metadata\"").unwrap(),
611            ClientErrorCode::InvalidClientMetadata
612        );
613
614        assert_eq!(
615            serde_json::from_str::<ClientErrorCode>("\"unknown_error_code\"").unwrap(),
616            ClientErrorCode::Unknown("unknown_error_code".to_owned())
617        );
618    }
619}