oauth2_types/
errors.rs

1// Copyright 2021, 2022 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Error types returned by an authorization server.
16
17use std::borrow::Cow;
18
19use serde::{Deserialize, Serialize};
20use serde_with::{DeserializeFromStr, SerializeDisplay};
21
22/// A client error returned by an authorization server.
23///
24/// To construct this with a default description for the error code, use its
25/// `From<ClientErrorCode>` implementation.
26#[derive(Debug, Serialize, Deserialize, Clone)]
27pub struct ClientError {
28    /// The error code.
29    pub error: ClientErrorCode,
30
31    /// A human-readable description of the error.
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub error_description: Option<Cow<'static, str>>,
34}
35
36impl ClientError {
37    /// Creates a new `ClientError` with the given error code and description.
38    #[must_use]
39    pub const fn new(error: ClientErrorCode, error_description: &'static str) -> Self {
40        Self {
41            error,
42            error_description: Some(Cow::Borrowed(error_description)),
43        }
44    }
45
46    /// Changes the description of this `ClientError` with the given `String`.
47    #[must_use]
48    pub fn with_description(mut self, description: String) -> Self {
49        self.error_description = Some(Cow::Owned(description));
50        self
51    }
52}
53
54impl From<ClientErrorCode> for ClientError {
55    fn from(error: ClientErrorCode) -> Self {
56        let desc = error.default_description();
57        Self::new(error, desc)
58    }
59}
60
61/// Client error codes defined in OAuth2.0, OpenID Connect and their extensions.
62#[derive(Debug, Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr)]
63pub enum ClientErrorCode {
64    /// `invalid_request`
65    ///
66    /// The request is missing a required parameter, includes an invalid
67    /// parameter value, includes a parameter more than once, or is otherwise
68    /// malformed.
69    ///
70    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
71    InvalidRequest,
72
73    /// `invalid_client`
74    ///
75    /// Client authentication failed (e.g., unknown client, no client
76    /// authentication included, or unsupported authentication method).
77    ///
78    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
79    InvalidClient,
80
81    /// `invalid_grant`
82    ///
83    /// The provided authorization grant (e.g., authorization code, resource
84    /// owner credentials) or refresh token is invalid, expired, revoked, does
85    /// not match the redirection URI used in the authorization request, or was
86    /// issued to another client.
87    ///
88    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
89    InvalidGrant,
90
91    /// `unauthorized_client`
92    ///
93    /// The authenticated client is not authorized to use this authorization
94    /// grant type.
95    ///
96    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
97    UnauthorizedClient,
98
99    /// `unsupported_grant_type`
100    ///
101    /// The authorization grant type is not supported by the authorization
102    /// server.
103    ///
104    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
105    UnsupportedGrantType,
106
107    /// `access_denied`
108    ///
109    /// The resource owner or authorization server denied the request.
110    ///
111    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
112    AccessDenied,
113
114    /// `unsupported_response_type`
115    ///
116    /// The authorization server does not support obtaining an authorization
117    /// code using this method.
118    ///
119    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
120    UnsupportedResponseType,
121
122    /// `invalid_scope`
123    ///
124    /// The requested scope is invalid, unknown, malformed, or exceeds the scope
125    /// granted by the resource owner.
126    ///
127    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
128    InvalidScope,
129
130    /// `server_error`
131    ///
132    /// The authorization server encountered an unexpected condition that
133    /// prevented it from fulfilling the request.
134    ///
135    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
136    ServerError,
137
138    /// `temporarily_unavailable`
139    ///
140    /// The authorization server is currently unable to handle the request due
141    /// to a temporary overloading or maintenance of the server.
142    ///
143    /// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
144    TemporarilyUnavailable,
145
146    /// `interaction_required`
147    ///
148    /// The authorization server requires end-user interaction of some form to
149    /// proceed.
150    ///
151    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
152    InteractionRequired,
153
154    /// `login_required`
155    ///
156    /// The authorization server requires end-user authentication.
157    ///
158    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
159    LoginRequired,
160
161    /// `account_selection_required`
162    ///
163    /// The end-user is required to select a session at the authorization
164    /// server.
165    ///
166    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
167    AccountSelectionRequired,
168
169    /// `consent_required`
170    ///
171    /// The authorization server requires end-user consent.
172    ///
173    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
174    ConsentRequired,
175
176    /// `invalid_request_uri`
177    ///
178    /// The `request_uri` in the authorization request returns an error or
179    /// contains invalid data.
180    ///
181    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
182    InvalidRequestUri,
183
184    /// `invalid_request_object`
185    ///
186    /// The request parameter contains an invalid request object.
187    ///
188    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
189    InvalidRequestObject,
190
191    /// `request_not_supported`
192    ///
193    /// The authorization server does not support use of the `request`
194    /// parameter.
195    ///
196    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
197    RequestNotSupported,
198
199    /// `request_uri_not_supported`
200    ///
201    /// The authorization server does not support use of the `request_uri`
202    /// parameter.
203    ///
204    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
205    RequestUriNotSupported,
206
207    /// `registration_not_supported`
208    ///
209    /// The authorization server does not support use of the `registration`
210    /// parameter.
211    ///
212    /// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
213    RegistrationNotSupported,
214
215    /// `invalid_redirect_uri`
216    ///
217    /// The value of one or more redirection URIs is invalid.
218    ///
219    /// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2).
220    InvalidRedirectUri,
221
222    /// `invalid_client_metadata`
223    ///
224    /// The value of one of the client metadata fields is invalid and the server
225    /// has rejected this request.
226    ///
227    /// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2).
228    InvalidClientMetadata,
229
230    /// `authorization_pending`
231    ///
232    /// The authorization request is still pending as the end user hasn't yet
233    /// completed the user-interaction steps.
234    ///
235    /// The client should repeat the access token request to the token endpoint
236    /// (a process known as polling).  Before each new request, the client
237    /// must wait at least the number of seconds specified by the `interval`
238    /// parameter of the device authorization response, or 5 seconds if none was
239    /// provided, and respect any increase in the polling interval required
240    /// by the [`ClientErrorCode::SlowDown`] error.
241    ///
242    /// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
243    AuthorizationPending,
244
245    /// `slow_down`
246    ///
247    /// A variant of [`ClientErrorCode::AuthorizationPending`], the
248    /// authorization request is still pending and polling should continue,
249    /// but the interval must be increased by 5 seconds for this and all
250    /// subsequent requests.
251    ///
252    /// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
253    SlowDown,
254
255    /// `expired_token`
256    ///
257    /// The `device_code` has expired, and the device authorization session has
258    /// concluded.
259    ///
260    /// The client may commence a new device authorization request but should
261    /// wait for user interaction before restarting to avoid unnecessary
262    /// polling.
263    ///
264    /// From [RFC8628](https://www.rfc-editor.org/rfc/rfc8628#section-3.5).
265    ExpiredToken,
266
267    /// `unsupported_token_type`
268    ///
269    /// The authorization server does not support the revocation of the
270    /// presented token type.  That is, the client tried to revoke an access
271    /// token on a server not supporting this feature.
272    ///
273    /// From [RFC7009](https://www.rfc-editor.org/rfc/rfc7009#section-2.2.1).
274    UnsupportedTokenType,
275
276    /// Another error code.
277    Unknown(String),
278}
279
280impl core::fmt::Display for ClientErrorCode {
281    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
282        match self {
283            ClientErrorCode::InvalidRequest => f.write_str("invalid_request"),
284            ClientErrorCode::InvalidClient => f.write_str("invalid_client"),
285            ClientErrorCode::InvalidGrant => f.write_str("invalid_grant"),
286            ClientErrorCode::UnauthorizedClient => f.write_str("unauthorized_client"),
287            ClientErrorCode::UnsupportedGrantType => f.write_str("unsupported_grant_type"),
288            ClientErrorCode::AccessDenied => f.write_str("access_denied"),
289            ClientErrorCode::UnsupportedResponseType => f.write_str("unsupported_response_type"),
290            ClientErrorCode::InvalidScope => f.write_str("invalid_scope"),
291            ClientErrorCode::ServerError => f.write_str("server_error"),
292            ClientErrorCode::TemporarilyUnavailable => f.write_str("temporarily_unavailable"),
293            ClientErrorCode::InteractionRequired => f.write_str("interaction_required"),
294            ClientErrorCode::LoginRequired => f.write_str("login_required"),
295            ClientErrorCode::AccountSelectionRequired => f.write_str("account_selection_required"),
296            ClientErrorCode::ConsentRequired => f.write_str("consent_required"),
297            ClientErrorCode::InvalidRequestUri => f.write_str("invalid_request_uri"),
298            ClientErrorCode::InvalidRequestObject => f.write_str("invalid_request_object"),
299            ClientErrorCode::RequestNotSupported => f.write_str("request_not_supported"),
300            ClientErrorCode::RequestUriNotSupported => f.write_str("request_uri_not_supported"),
301            ClientErrorCode::RegistrationNotSupported => f.write_str("registration_not_supported"),
302            ClientErrorCode::InvalidRedirectUri => f.write_str("invalid_redirect_uri"),
303            ClientErrorCode::InvalidClientMetadata => f.write_str("invalid_client_metadata"),
304            ClientErrorCode::AuthorizationPending => f.write_str("authorization_pending"),
305            ClientErrorCode::SlowDown => f.write_str("slow_down"),
306            ClientErrorCode::ExpiredToken => f.write_str("expired_token"),
307            ClientErrorCode::UnsupportedTokenType => f.write_str("unsupported_token_type"),
308            ClientErrorCode::Unknown(value) => f.write_str(value),
309        }
310    }
311}
312
313impl core::str::FromStr for ClientErrorCode {
314    type Err = core::convert::Infallible;
315
316    fn from_str(s: &str) -> Result<Self, Self::Err> {
317        match s {
318            "invalid_request" => Ok(ClientErrorCode::InvalidRequest),
319            "invalid_client" => Ok(ClientErrorCode::InvalidClient),
320            "invalid_grant" => Ok(ClientErrorCode::InvalidGrant),
321            "unauthorized_client" => Ok(ClientErrorCode::UnauthorizedClient),
322            "unsupported_grant_type" => Ok(ClientErrorCode::UnsupportedGrantType),
323            "access_denied" => Ok(ClientErrorCode::AccessDenied),
324            "unsupported_response_type" => Ok(ClientErrorCode::UnsupportedResponseType),
325            "invalid_scope" => Ok(ClientErrorCode::InvalidScope),
326            "server_error" => Ok(ClientErrorCode::ServerError),
327            "temporarily_unavailable" => Ok(ClientErrorCode::TemporarilyUnavailable),
328            "interaction_required" => Ok(ClientErrorCode::InteractionRequired),
329            "login_required" => Ok(ClientErrorCode::LoginRequired),
330            "account_selection_required" => Ok(ClientErrorCode::AccountSelectionRequired),
331            "consent_required" => Ok(ClientErrorCode::ConsentRequired),
332            "invalid_request_uri" => Ok(ClientErrorCode::InvalidRequestUri),
333            "invalid_request_object" => Ok(ClientErrorCode::InvalidRequestObject),
334            "request_not_supported" => Ok(ClientErrorCode::RequestNotSupported),
335            "request_uri_not_supported" => Ok(ClientErrorCode::RequestUriNotSupported),
336            "registration_not_supported" => Ok(ClientErrorCode::RegistrationNotSupported),
337            "invalid_redirect_uri" => Ok(ClientErrorCode::InvalidRedirectUri),
338            "invalid_client_metadata" => Ok(ClientErrorCode::InvalidClientMetadata),
339            "authorization_pending" => Ok(ClientErrorCode::AuthorizationPending),
340            "slow_down" => Ok(ClientErrorCode::SlowDown),
341            "expired_token" => Ok(ClientErrorCode::ExpiredToken),
342            "unsupported_token_type" => Ok(ClientErrorCode::UnsupportedTokenType),
343            _ => Ok(ClientErrorCode::Unknown(s.to_owned())),
344        }
345    }
346}
347
348impl ClientErrorCode {
349    /// Get the default description for this `ClientErrorCode`.
350    ///
351    /// Note that [`ClientErrorCode::Unknown`] returns an empty string.
352    #[must_use]
353    pub fn default_description(&self) -> &'static str {
354        match self {
355            ClientErrorCode::InvalidRequest => {
356                "The request is missing a required parameter, includes an \
357                invalid parameter value, includes a parameter more than once, \
358                or is otherwise malformed."
359            }
360            ClientErrorCode::InvalidClient => "Client authentication failed.",
361            ClientErrorCode::InvalidGrant => {
362                "The provided access grant is invalid, expired, or revoked."
363            }
364            ClientErrorCode::UnauthorizedClient => {
365                "The client is not authorized to request an access token using this method."
366            }
367            ClientErrorCode::UnsupportedGrantType => {
368                "The authorization grant type is not supported by the authorization server."
369            }
370            ClientErrorCode::AccessDenied => {
371                "The resource owner or authorization server denied the request."
372            }
373            ClientErrorCode::UnsupportedResponseType => {
374                "The authorization server does not support obtaining an access \
375                token using this method."
376            }
377            ClientErrorCode::InvalidScope => {
378                "The requested scope is invalid, unknown, or malformed."
379            }
380            ClientErrorCode::ServerError => {
381                "The authorization server encountered an unexpected condition \
382                that prevented it from fulfilling the request."
383            }
384            ClientErrorCode::TemporarilyUnavailable => {
385                "The authorization server is currently unable to handle the request \
386                due to a temporary overloading or maintenance of the server."
387            }
388            ClientErrorCode::InteractionRequired => {
389                "The Authorization Server requires End-User interaction of some form to proceed."
390            }
391            ClientErrorCode::LoginRequired => {
392                "The Authorization Server requires End-User authentication."
393            }
394            ClientErrorCode::AccountSelectionRequired => {
395                "The End-User is required to select a session at the Authorization Server."
396            }
397            ClientErrorCode::ConsentRequired => {
398                "The Authorization Server requires End-User consent."
399            }
400            ClientErrorCode::InvalidRequestUri => {
401                "The request_uri in the Authorization Request returns an error \
402                or contains invalid data."
403            }
404            ClientErrorCode::InvalidRequestObject => {
405                "The request parameter contains an invalid Request Object."
406            }
407            ClientErrorCode::RequestNotSupported => {
408                "The provider does not support use of the request parameter."
409            }
410            ClientErrorCode::RequestUriNotSupported => {
411                "The provider does not support use of the request_uri parameter."
412            }
413            ClientErrorCode::RegistrationNotSupported => {
414                "The provider does not support use of the registration parameter."
415            }
416            ClientErrorCode::InvalidRedirectUri => {
417                "The value of one or more redirection URIs is invalid."
418            }
419            ClientErrorCode::InvalidClientMetadata => {
420                "The value of one of the client metadata fields is invalid"
421            }
422            ClientErrorCode::AuthorizationPending => {
423                "The authorization request is still pending"
424            }
425            ClientErrorCode::SlowDown => {
426                "The interval must be increased by 5 seconds for this and all subsequent requests"
427            }
428            ClientErrorCode::ExpiredToken => {
429                "The \"device_code\" has expired, and the device authorization session has concluded"
430            }
431            ClientErrorCode::UnsupportedTokenType => {
432                "The authorization server does not support the revocation of the presented token type."
433            },
434            ClientErrorCode::Unknown(_) => "",
435        }
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    #[test]
444    fn serialize_client_error_code() {
445        assert_eq!(
446            serde_json::to_string(&ClientErrorCode::InvalidRequest).unwrap(),
447            "\"invalid_request\""
448        );
449        assert_eq!(
450            serde_json::to_string(&ClientErrorCode::InvalidClient).unwrap(),
451            "\"invalid_client\""
452        );
453        assert_eq!(
454            serde_json::to_string(&ClientErrorCode::InvalidGrant).unwrap(),
455            "\"invalid_grant\""
456        );
457        assert_eq!(
458            serde_json::to_string(&ClientErrorCode::UnauthorizedClient).unwrap(),
459            "\"unauthorized_client\""
460        );
461        assert_eq!(
462            serde_json::to_string(&ClientErrorCode::UnsupportedGrantType).unwrap(),
463            "\"unsupported_grant_type\""
464        );
465        assert_eq!(
466            serde_json::to_string(&ClientErrorCode::AccessDenied).unwrap(),
467            "\"access_denied\""
468        );
469        assert_eq!(
470            serde_json::to_string(&ClientErrorCode::UnsupportedResponseType).unwrap(),
471            "\"unsupported_response_type\""
472        );
473        assert_eq!(
474            serde_json::to_string(&ClientErrorCode::InvalidScope).unwrap(),
475            "\"invalid_scope\""
476        );
477        assert_eq!(
478            serde_json::to_string(&ClientErrorCode::ServerError).unwrap(),
479            "\"server_error\""
480        );
481        assert_eq!(
482            serde_json::to_string(&ClientErrorCode::TemporarilyUnavailable).unwrap(),
483            "\"temporarily_unavailable\""
484        );
485        assert_eq!(
486            serde_json::to_string(&ClientErrorCode::InteractionRequired).unwrap(),
487            "\"interaction_required\""
488        );
489        assert_eq!(
490            serde_json::to_string(&ClientErrorCode::LoginRequired).unwrap(),
491            "\"login_required\""
492        );
493        assert_eq!(
494            serde_json::to_string(&ClientErrorCode::AccountSelectionRequired).unwrap(),
495            "\"account_selection_required\""
496        );
497        assert_eq!(
498            serde_json::to_string(&ClientErrorCode::ConsentRequired).unwrap(),
499            "\"consent_required\""
500        );
501        assert_eq!(
502            serde_json::to_string(&ClientErrorCode::InvalidRequestUri).unwrap(),
503            "\"invalid_request_uri\""
504        );
505        assert_eq!(
506            serde_json::to_string(&ClientErrorCode::InvalidRequestObject).unwrap(),
507            "\"invalid_request_object\""
508        );
509        assert_eq!(
510            serde_json::to_string(&ClientErrorCode::RequestNotSupported).unwrap(),
511            "\"request_not_supported\""
512        );
513        assert_eq!(
514            serde_json::to_string(&ClientErrorCode::RequestUriNotSupported).unwrap(),
515            "\"request_uri_not_supported\""
516        );
517        assert_eq!(
518            serde_json::to_string(&ClientErrorCode::RegistrationNotSupported).unwrap(),
519            "\"registration_not_supported\""
520        );
521        assert_eq!(
522            serde_json::to_string(&ClientErrorCode::InvalidRedirectUri).unwrap(),
523            "\"invalid_redirect_uri\""
524        );
525        assert_eq!(
526            serde_json::to_string(&ClientErrorCode::InvalidClientMetadata).unwrap(),
527            "\"invalid_client_metadata\""
528        );
529
530        assert_eq!(
531            serde_json::to_string(&ClientErrorCode::Unknown("unknown_error_code".to_owned()))
532                .unwrap(),
533            "\"unknown_error_code\""
534        );
535    }
536
537    #[test]
538    fn deserialize_client_error_code() {
539        assert_eq!(
540            serde_json::from_str::<ClientErrorCode>("\"invalid_request\"").unwrap(),
541            ClientErrorCode::InvalidRequest
542        );
543        assert_eq!(
544            serde_json::from_str::<ClientErrorCode>("\"invalid_client\"").unwrap(),
545            ClientErrorCode::InvalidClient
546        );
547        assert_eq!(
548            serde_json::from_str::<ClientErrorCode>("\"invalid_grant\"").unwrap(),
549            ClientErrorCode::InvalidGrant
550        );
551        assert_eq!(
552            serde_json::from_str::<ClientErrorCode>("\"unauthorized_client\"").unwrap(),
553            ClientErrorCode::UnauthorizedClient
554        );
555        assert_eq!(
556            serde_json::from_str::<ClientErrorCode>("\"unsupported_grant_type\"").unwrap(),
557            ClientErrorCode::UnsupportedGrantType
558        );
559        assert_eq!(
560            serde_json::from_str::<ClientErrorCode>("\"access_denied\"").unwrap(),
561            ClientErrorCode::AccessDenied
562        );
563        assert_eq!(
564            serde_json::from_str::<ClientErrorCode>("\"unsupported_response_type\"").unwrap(),
565            ClientErrorCode::UnsupportedResponseType
566        );
567        assert_eq!(
568            serde_json::from_str::<ClientErrorCode>("\"invalid_scope\"").unwrap(),
569            ClientErrorCode::InvalidScope
570        );
571        assert_eq!(
572            serde_json::from_str::<ClientErrorCode>("\"server_error\"").unwrap(),
573            ClientErrorCode::ServerError
574        );
575        assert_eq!(
576            serde_json::from_str::<ClientErrorCode>("\"temporarily_unavailable\"").unwrap(),
577            ClientErrorCode::TemporarilyUnavailable
578        );
579        assert_eq!(
580            serde_json::from_str::<ClientErrorCode>("\"interaction_required\"").unwrap(),
581            ClientErrorCode::InteractionRequired
582        );
583        assert_eq!(
584            serde_json::from_str::<ClientErrorCode>("\"login_required\"").unwrap(),
585            ClientErrorCode::LoginRequired
586        );
587        assert_eq!(
588            serde_json::from_str::<ClientErrorCode>("\"account_selection_required\"").unwrap(),
589            ClientErrorCode::AccountSelectionRequired
590        );
591        assert_eq!(
592            serde_json::from_str::<ClientErrorCode>("\"consent_required\"").unwrap(),
593            ClientErrorCode::ConsentRequired
594        );
595        assert_eq!(
596            serde_json::from_str::<ClientErrorCode>("\"invalid_request_uri\"").unwrap(),
597            ClientErrorCode::InvalidRequestUri
598        );
599        assert_eq!(
600            serde_json::from_str::<ClientErrorCode>("\"invalid_request_object\"").unwrap(),
601            ClientErrorCode::InvalidRequestObject
602        );
603        assert_eq!(
604            serde_json::from_str::<ClientErrorCode>("\"request_not_supported\"").unwrap(),
605            ClientErrorCode::RequestNotSupported
606        );
607        assert_eq!(
608            serde_json::from_str::<ClientErrorCode>("\"request_uri_not_supported\"").unwrap(),
609            ClientErrorCode::RequestUriNotSupported
610        );
611        assert_eq!(
612            serde_json::from_str::<ClientErrorCode>("\"registration_not_supported\"").unwrap(),
613            ClientErrorCode::RegistrationNotSupported
614        );
615        assert_eq!(
616            serde_json::from_str::<ClientErrorCode>("\"invalid_redirect_uri\"").unwrap(),
617            ClientErrorCode::InvalidRedirectUri
618        );
619        assert_eq!(
620            serde_json::from_str::<ClientErrorCode>("\"invalid_client_metadata\"").unwrap(),
621            ClientErrorCode::InvalidClientMetadata
622        );
623
624        assert_eq!(
625            serde_json::from_str::<ClientErrorCode>("\"unknown_error_code\"").unwrap(),
626            ClientErrorCode::Unknown("unknown_error_code".to_owned())
627        );
628    }
629}