openid_client/client/
client.rs

1use std::{collections::HashMap, time::Duration};
2
3use serde_json::Value;
4
5use crate::{
6    helpers::{convert_json_to, now, validate_url},
7    http::request_async,
8    issuer::Issuer,
9    jwks::Jwks,
10    types::{
11        http_client::HttpMethod, ClientMetadata, ClientOptions, ClientRegistrationOptions, Fapi,
12        HttpRequest, OidcClientError, OidcHttpClient, OidcReturnType,
13    },
14};
15
16use super::dpop_nonce_cache::DPoPNonceCache;
17
18/// # Client instance
19#[derive(Debug)]
20pub struct Client {
21    pub(crate) client_id: String,
22    pub(crate) client_secret: Option<String>,
23    pub(crate) registration_access_token: Option<String>,
24    pub(crate) registration_client_uri: Option<String>,
25    pub(crate) client_id_issued_at: Option<i64>,
26    pub(crate) client_secret_expires_at: Option<i64>,
27    pub(crate) token_endpoint_auth_method: Option<String>,
28    pub(crate) token_endpoint_auth_signing_alg: Option<String>,
29    pub(crate) introspection_endpoint_auth_method: Option<String>,
30    pub(crate) introspection_endpoint_auth_signing_alg: Option<String>,
31    pub(crate) revocation_endpoint_auth_method: Option<String>,
32    pub(crate) revocation_endpoint_auth_signing_alg: Option<String>,
33    pub(crate) redirect_uri: Option<String>,
34    pub(crate) redirect_uris: Option<Vec<String>>,
35    pub(crate) response_type: Option<String>,
36    pub(crate) response_types: Vec<String>,
37    pub(crate) grant_types: Vec<String>,
38    pub(crate) jwks_uri: Option<String>,
39    pub(crate) jwks: Option<Jwks>,
40    pub(crate) sector_identifier_uri: Option<String>,
41    pub(crate) subject_type: Option<String>,
42    pub(crate) id_token_signed_response_alg: String,
43    pub(crate) id_token_encrypted_response_alg: Option<String>,
44    pub(crate) id_token_encrypted_response_enc: Option<String>,
45    pub(crate) userinfo_signed_response_alg: Option<String>,
46    pub(crate) userinfo_encrypted_response_alg: Option<String>,
47    pub(crate) userinfo_encrypted_response_enc: Option<String>,
48    pub(crate) request_object_signing_alg: Option<String>,
49    pub(crate) request_object_encryption_alg: Option<String>,
50    pub(crate) request_object_encryption_enc: Option<String>,
51    pub(crate) default_max_age: Option<u64>,
52    pub(crate) require_auth_time: Option<bool>,
53    pub(crate) default_acr_values: Option<Vec<String>>,
54    pub(crate) initiate_login_uri: Option<String>,
55    pub(crate) request_uris: Option<String>,
56    pub(crate) tls_client_certificate_bound_access_tokens: Option<bool>,
57    pub(crate) post_logout_redirect_uris: Option<Vec<String>>,
58    pub(crate) authorization_encrypted_response_alg: Option<String>,
59    pub(crate) authorization_encrypted_response_enc: Option<String>,
60    pub(crate) authorization_signed_response_alg: Option<String>,
61    pub(crate) private_jwks: Option<Jwks>,
62    pub(crate) issuer: Option<Issuer>,
63    pub(crate) client_options: Option<ClientOptions>,
64    pub(crate) skip_max_age_check: bool,
65    pub(crate) skip_nonce_check: bool,
66    pub(crate) clock_tolerance: Duration,
67    pub(crate) fapi: Option<Fapi>,
68    pub(crate) now: fn() -> i64,
69    pub(crate) dpop_nonce_cache: DPoPNonceCache,
70    pub(crate) dpop_bound_access_tokens: Option<bool>,
71    pub(crate) other_fields: HashMap<String, Value>,
72}
73
74impl Client {
75    pub(crate) fn default(fapi: Option<Fapi>) -> Self {
76        let mut client = Self {
77            client_id: String::new(),
78            client_secret: None,
79            registration_access_token: None,
80            registration_client_uri: None,
81            client_id_issued_at: None,
82            client_secret_expires_at: None,
83            token_endpoint_auth_method: Some("client_secret_basic".to_string()),
84            token_endpoint_auth_signing_alg: None,
85            introspection_endpoint_auth_method: None,
86            introspection_endpoint_auth_signing_alg: None,
87            revocation_endpoint_auth_method: None,
88            revocation_endpoint_auth_signing_alg: None,
89            redirect_uri: None,
90            redirect_uris: None,
91            response_type: None,
92            response_types: vec!["code".to_string()],
93            grant_types: vec!["authorization_code".to_string()],
94            jwks_uri: None,
95            jwks: None,
96            sector_identifier_uri: None,
97            subject_type: None,
98            id_token_signed_response_alg: "RS256".to_string(),
99            id_token_encrypted_response_alg: None,
100            id_token_encrypted_response_enc: Some("A128CBC-HS256".to_string()),
101            userinfo_signed_response_alg: None,
102            userinfo_encrypted_response_alg: None,
103            userinfo_encrypted_response_enc: None,
104            request_object_signing_alg: None,
105            request_object_encryption_alg: None,
106            request_object_encryption_enc: None,
107            default_max_age: None,
108            require_auth_time: None,
109            default_acr_values: None,
110            initiate_login_uri: None,
111            request_uris: None,
112            private_jwks: None,
113            issuer: None,
114            tls_client_certificate_bound_access_tokens: None,
115            post_logout_redirect_uris: None,
116            authorization_encrypted_response_alg: None,
117            authorization_encrypted_response_enc: None,
118            authorization_signed_response_alg: None,
119            other_fields: HashMap::new(),
120            client_options: None,
121            skip_max_age_check: false,
122            skip_nonce_check: false,
123            clock_tolerance: Duration::from_secs(0),
124            fapi: None,
125            now,
126            dpop_nonce_cache: DPoPNonceCache::new(),
127            dpop_bound_access_tokens: None,
128        };
129
130        match fapi.as_ref() {
131            Some(Fapi::V1) => {
132                client.grant_types = vec!["authorization_code".to_string(), "implicit".to_string()];
133                client.id_token_signed_response_alg = "PS256".to_string();
134                client.authorization_signed_response_alg = Some("PS256".to_string());
135                client.response_types = vec!["code".to_string(), "id_token".to_string()];
136                client.tls_client_certificate_bound_access_tokens = Some(true);
137                client.token_endpoint_auth_method = None;
138            }
139            Some(Fapi::V2) => {
140                client.id_token_signed_response_alg = "PS256".to_string();
141                client.authorization_signed_response_alg = Some("PS256".to_string());
142                client.token_endpoint_auth_method = None;
143            }
144            None => {}
145        };
146
147        client.fapi = fapi;
148
149        client
150    }
151
152    pub(crate) fn from_internal(
153        metadata: ClientMetadata,
154        issuer: Option<&Issuer>,
155        jwks: Option<Jwks>,
156        options: Option<ClientOptions>,
157        fapi: Option<Fapi>,
158    ) -> OidcReturnType<Self> {
159        let mut valid_client_id = true;
160
161        if let Some(client_id) = &metadata.client_id {
162            if client_id.is_empty() {
163                valid_client_id = false;
164            }
165        } else {
166            valid_client_id = false;
167        }
168
169        if !valid_client_id {
170            return Err(Box::new(OidcClientError::new_type_error(
171                "client_id is required",
172                None,
173            )));
174        }
175
176        let mut client = Self {
177            client_id: metadata.client_id.unwrap(),
178            client_secret: metadata.client_secret,
179            sector_identifier_uri: metadata.sector_identifier_uri,
180            subject_type: metadata.subject_type,
181            registration_access_token: metadata.registration_access_token,
182            registration_client_uri: metadata.registration_client_uri,
183            client_id_issued_at: metadata.client_id_issued_at,
184            client_secret_expires_at: metadata.client_secret_expires_at,
185            id_token_encrypted_response_alg: metadata.id_token_encrypted_response_alg,
186            userinfo_signed_response_alg: metadata.userinfo_signed_response_alg,
187            userinfo_encrypted_response_alg: metadata.userinfo_encrypted_response_alg,
188            userinfo_encrypted_response_enc: metadata.userinfo_encrypted_response_enc,
189            request_object_signing_alg: metadata.request_object_signing_alg,
190            request_object_encryption_alg: metadata.request_object_encryption_alg,
191            request_object_encryption_enc: metadata.request_object_encryption_enc,
192            jwks_uri: metadata.jwks_uri,
193            jwks: metadata.jwks,
194            default_max_age: metadata.default_max_age,
195            require_auth_time: metadata.require_auth_time,
196            default_acr_values: metadata.default_acr_values,
197            initiate_login_uri: metadata.initiate_login_uri,
198            request_uris: metadata.request_uris,
199            post_logout_redirect_uris: metadata.post_logout_redirect_uris,
200            authorization_encrypted_response_alg: metadata.authorization_encrypted_response_alg,
201            authorization_encrypted_response_enc: metadata.authorization_encrypted_response_enc,
202            dpop_bound_access_tokens: metadata.dpop_bound_access_tokens,
203            other_fields: metadata.other_fields,
204            ..Client::default(fapi)
205        };
206
207        if metadata
208            .tls_client_certificate_bound_access_tokens
209            .is_some()
210        {
211            client.tls_client_certificate_bound_access_tokens =
212                metadata.tls_client_certificate_bound_access_tokens;
213        }
214
215        if metadata.authorization_signed_response_alg.is_some() {
216            client.authorization_signed_response_alg = metadata.authorization_signed_response_alg;
217        }
218
219        client.client_options = options;
220
221        if client.jwks_uri.is_some() && client.jwks.is_some() {
222            client.jwks = None;
223        }
224
225        if metadata.response_type.is_some() && metadata.response_types.is_some() {
226            return Err(Box::new(OidcClientError::new_type_error(
227                "provide a response_type or response_types, not both",
228                None,
229            )));
230        }
231
232        if let Some(response_type) = &metadata.response_type {
233            client.response_type = Some(response_type.clone());
234            client.response_types = vec![response_type.clone()];
235        }
236
237        if let Some(response_types) = &metadata.response_types {
238            client.response_types = response_types.clone().to_vec();
239        }
240
241        if metadata.redirect_uri.is_some() && metadata.redirect_uris.is_some() {
242            return Err(Box::new(OidcClientError::new_type_error(
243                "provide a redirect_uri or redirect_uris, not both",
244                None,
245            )));
246        }
247
248        if let Some(redirect_uri) = &metadata.redirect_uri {
249            client.redirect_uri = Some(redirect_uri.clone());
250            client.redirect_uris = Some(vec![redirect_uri.clone()])
251        }
252
253        if let Some(redirect_uris) = &metadata.redirect_uris {
254            client.redirect_uris = Some(redirect_uris.clone().to_vec());
255        }
256
257        if let Some(team) = metadata.token_endpoint_auth_method {
258            client.token_endpoint_auth_method = Some(team);
259        } else if let Some(iss) = issuer {
260            if let Some(teams) = &iss.token_endpoint_auth_methods_supported {
261                if let Some(team) = &client.token_endpoint_auth_method {
262                    if !teams.contains(team) && teams.contains(&"client_secret_post".to_string()) {
263                        client.token_endpoint_auth_method = Some("client_secret_post".to_string());
264                    }
265                }
266            }
267        }
268
269        if metadata.token_endpoint_auth_signing_alg.is_some() {
270            client.token_endpoint_auth_signing_alg = metadata.token_endpoint_auth_signing_alg;
271        }
272
273        client.introspection_endpoint_auth_method = metadata
274            .introspection_endpoint_auth_method
275            .or(client.token_endpoint_auth_method.clone());
276
277        client.introspection_endpoint_auth_signing_alg = metadata
278            .introspection_endpoint_auth_signing_alg
279            .or(client.token_endpoint_auth_signing_alg.clone());
280
281        client.revocation_endpoint_auth_method = metadata
282            .revocation_endpoint_auth_method
283            .or(client.token_endpoint_auth_method.clone());
284
285        client.revocation_endpoint_auth_signing_alg = metadata
286            .revocation_endpoint_auth_signing_alg
287            .or(client.token_endpoint_auth_signing_alg.clone());
288
289        if let Some(iss) = issuer {
290            if iss.token_endpoint.is_some() {
291                Self::assert_signing_alg_values_support(
292                    &client.token_endpoint_auth_method.clone(),
293                    &client.token_endpoint_auth_signing_alg,
294                    &iss.token_endpoint_auth_signing_alg_values_supported,
295                    "token",
296                )?;
297            }
298
299            if iss.introspection_endpoint.is_some() {
300                Self::assert_signing_alg_values_support(
301                    &client.introspection_endpoint_auth_method,
302                    &client.introspection_endpoint_auth_signing_alg,
303                    &iss.token_endpoint_auth_signing_alg_values_supported,
304                    "introspection",
305                )?;
306            }
307
308            if iss.revocation_endpoint.is_some() {
309                Self::assert_signing_alg_values_support(
310                    &client.revocation_endpoint_auth_method,
311                    &client.revocation_endpoint_auth_signing_alg,
312                    &iss.token_endpoint_auth_signing_alg_values_supported,
313                    "revocation",
314                )?;
315            }
316
317            client.issuer = Some(iss.clone());
318        }
319
320        if metadata.id_token_encrypted_response_enc.is_some() {
321            client.id_token_encrypted_response_enc = metadata.id_token_encrypted_response_enc;
322        }
323
324        if jwks.is_some() {
325            client.private_jwks = jwks;
326        }
327
328        if let Some(alg) = metadata.id_token_signed_response_alg {
329            client.id_token_signed_response_alg = alg;
330        }
331
332        if client.is_fapi1() {
333            match client.token_endpoint_auth_method.as_deref() {
334                Some("private_key_jwt") => {
335                    if client.private_jwks.is_none() {
336                        return Err(Box::new(OidcClientError::new_type_error(
337                            "jwks is required",
338                            None,
339                        )));
340                    }
341                }
342                Some("self_signed_tls_client_auth") | Some("tls_client_auth") => {}
343                Some(_) => {
344                    return Err(Box::new(OidcClientError::new_type_error(
345                        "invalid or unsupported token_endpoint_auth_method",
346                        None,
347                    )));
348                }
349                None => {
350                    return Err(Box::new(OidcClientError::new_type_error(
351                        "token_endpoint_auth_method is required",
352                        None,
353                    )));
354                }
355            };
356        }
357
358        if client.is_fapi2() {
359            match (
360                client.tls_client_certificate_bound_access_tokens.as_ref(),
361                client.dpop_bound_access_tokens.as_ref(),
362            ) {
363                (Some(&false), Some(&false))
364                | (Some(&false), None)
365                | (None, Some(&false))
366                | (None, None) => return Err(Box::new(OidcClientError::new_type_error(
367                    "one of tls_client_certificate_bound_access_tokens or dpop_bound_access_tokens must be true",
368                    None,
369                ))),
370
371                (Some(&true), Some(&true)) => return Err(Box::new(OidcClientError::new_type_error(
372                    "only one of tls_client_certificate_bound_access_tokens or dpop_bound_access_tokens must be true",
373                    None,
374                ))),
375
376                (_, _) => {}
377            };
378        }
379
380        Ok(client)
381    }
382
383    fn assert_signing_alg_values_support(
384        auth_method: &Option<String>,
385        supported_alg: &Option<String>,
386        issuer_supported_alg_values: &Option<Vec<String>>,
387        endpoint: &str,
388    ) -> OidcReturnType<()> {
389        if let Some(am) = auth_method {
390            if am.ends_with("_jwt")
391                && supported_alg.is_none()
392                && issuer_supported_alg_values.is_none()
393            {
394                return Err(Box::new(OidcClientError::new_type_error(
395                    &format!("{endpoint}_endpoint_auth_signing_alg_values_supported must be configured on the issuer if {endpoint}_endpoint_auth_signing_alg is not defined on a client"),
396                    None,
397                )));
398            }
399        }
400        Ok(())
401    }
402
403    /// Gets the extra fields in client
404    pub fn get_other_fields(&self) -> &HashMap<String, Value> {
405        &self.other_fields
406    }
407}
408
409/// Implementation for Client Read Methods
410impl Client {
411    /// # Creates a client from the [Client Read Endpoint](https://openid.net/specs/openid-connect-registration-1_0.html#ReadRequest)
412    ///
413    /// Creates a [Client] from the Client read endpoint.
414    ///
415    /// - `http_client` - The http client to make the request
416    /// - `registration_client_uri` - The client read endpoint
417    /// - `issuer` - [Issuer]
418    /// - `registration_access_token` - The access token to be sent with the request
419    /// - `jwks` - Private [Jwks] of the client
420    /// - `client_options` - The [ClientOptions]
421    /// - `fapi` - [Fapi] version.
422    pub async fn from_uri_async<T>(
423        http_client: &T,
424        registration_client_uri: &str,
425        issuer: &Issuer,
426        registration_access_token: Option<String>,
427        jwks: Option<Jwks>,
428        client_options: Option<ClientOptions>,
429        fapi: Option<Fapi>,
430    ) -> OidcReturnType<Self>
431    where
432        T: OidcHttpClient,
433    {
434        Self::jwks_only_private_keys_validation(jwks.as_ref())?;
435
436        let url = validate_url(registration_client_uri)?;
437
438        let mut headers = HashMap::new();
439        headers.insert("accept".to_string(), vec!["application/json".to_string()]);
440
441        if let Some(rat) = registration_access_token {
442            headers.insert("authorization".to_string(), vec![format!("Bearer {rat}")]);
443        }
444
445        let req = HttpRequest::new()
446            .url(url)
447            .method(HttpMethod::GET)
448            .expect_body(true)
449            .expect_status_code(200)
450            .expect_bearer(true)
451            .headers(headers);
452
453        let res = request_async(req, http_client).await?;
454
455        let client_metadata = convert_json_to::<ClientMetadata>(res.body.as_ref().unwrap())
456            .map_err(|_| {
457                OidcClientError::new_op_error(
458                    "invalid client metadata".to_string(),
459                    Some("error while deserializing".to_string()),
460                    None,
461                    Some(res),
462                )
463            })?;
464
465        Self::from_internal(client_metadata, Some(issuer), jwks, client_options, fapi)
466    }
467}
468
469/// Implementations for Dynamic Client Registration
470impl Client {
471    /// # Dynamic Client Registration
472    ///
473    /// Attempts a Dynamic Client Registration using the Issuer's `registration_endpoint`
474    ///
475    /// - `http_client` - The http client to make the request
476    /// - `issuer` - The [Issuer] client should be registered to.
477    /// - `client_metadata` - The [ClientMetadata] to be sent using the registration request.
478    /// - `register_options` - [ClientRegistrationOptions]
479    /// - `fapi` - [Fapi] version.
480    pub async fn register_async<T>(
481        http_client: &T,
482        issuer: &Issuer,
483        mut client_metadata: ClientMetadata,
484        register_options: Option<ClientRegistrationOptions>,
485        fapi: Option<Fapi>,
486    ) -> OidcReturnType<Self>
487    where
488        T: OidcHttpClient,
489    {
490        if issuer.registration_endpoint.is_none() {
491            return Err(Box::new(OidcClientError::new_type_error(
492                "registration_endpoint must be configured on the issuer",
493                None,
494            )));
495        }
496
497        let mut initial_access_token: Option<String> = None;
498        let mut jwks: Option<Jwks> = None;
499        let mut client_options: Option<ClientOptions> = None;
500
501        if let Some(options) = &register_options {
502            initial_access_token.clone_from(&options.initial_access_token);
503            jwks.clone_from(&options.jwks);
504            client_options = Some(options.client_options.clone());
505
506            if options.jwks.is_some()
507                && client_metadata.jwks_uri.is_none()
508                && client_metadata.jwks.is_none()
509            {
510                if let Some(jwks) = options.jwks.as_ref() {
511                    client_metadata.jwks = Some(jwks.get_public_jwks());
512                }
513            }
514        }
515
516        Self::jwks_only_private_keys_validation(jwks.as_ref())?;
517
518        let url = validate_url(issuer.registration_endpoint.as_ref().unwrap())?;
519
520        let body = serde_json::to_string(&client_metadata).map_err(|_| {
521            OidcClientError::new_error("client metadata is an invalid json format", None)
522        })?;
523
524        let mut headers = HashMap::new();
525        headers.insert("accept".to_string(), vec!["application/json".to_string()]);
526
527        if let Some(iat) = initial_access_token {
528            headers.insert("authorization".to_string(), vec![format!("Bearer {iat}")]);
529        }
530
531        let req = HttpRequest::new()
532            .url(url)
533            .method(HttpMethod::POST)
534            .expect_body(true)
535            .expect_status_code(201)
536            .expect_bearer(true)
537            .headers(headers)
538            .json(body);
539
540        let response = request_async(req, http_client).await?;
541
542        let client_metadata = convert_json_to::<ClientMetadata>(response.body.as_ref().unwrap())
543            .map_err(|_| {
544                OidcClientError::new_op_error(
545                    "invalid client metadata".to_string(),
546                    None,
547                    None,
548                    Some(response),
549                )
550            })?;
551
552        Self::from_internal(client_metadata, Some(issuer), jwks, client_options, fapi)
553    }
554
555    /// # Get Client Metadata
556    /// Gets the [ClientMetadata] of this [Client] instance
557    pub fn metadata(&self) -> ClientMetadata {
558        ClientMetadata {
559            client_id: Some(self.client_id.clone()),
560            client_secret: self.client_secret.clone(),
561            registration_access_token: self.registration_access_token.clone(),
562            registration_client_uri: self.registration_client_uri.clone(),
563            client_id_issued_at: self.client_id_issued_at,
564            client_secret_expires_at: self.client_secret_expires_at,
565            token_endpoint_auth_method: self.token_endpoint_auth_method.clone(),
566            token_endpoint_auth_signing_alg: self.token_endpoint_auth_signing_alg.clone(),
567            introspection_endpoint_auth_method: self.introspection_endpoint_auth_method.clone(),
568            introspection_endpoint_auth_signing_alg: self
569                .introspection_endpoint_auth_signing_alg
570                .clone(),
571            revocation_endpoint_auth_method: self.revocation_endpoint_auth_method.clone(),
572            revocation_endpoint_auth_signing_alg: self.revocation_endpoint_auth_signing_alg.clone(),
573            redirect_uri: self.redirect_uri.clone(),
574            redirect_uris: self.redirect_uris.clone(),
575            response_type: self.response_type.clone(),
576            response_types: Some(self.response_types.clone()),
577            grant_types: Some(self.grant_types.clone()),
578            jwks_uri: self.jwks_uri.clone(),
579            jwks: self.jwks.clone(),
580            sector_identifier_uri: self.sector_identifier_uri.clone(),
581            subject_type: self.subject_type.clone(),
582            id_token_signed_response_alg: Some(self.id_token_signed_response_alg.clone()),
583            id_token_encrypted_response_alg: self.id_token_encrypted_response_alg.clone(),
584            id_token_encrypted_response_enc: self.id_token_encrypted_response_enc.clone(),
585            userinfo_signed_response_alg: self.userinfo_signed_response_alg.clone(),
586            userinfo_encrypted_response_alg: self.userinfo_encrypted_response_alg.clone(),
587            userinfo_encrypted_response_enc: self.userinfo_encrypted_response_enc.clone(),
588            request_object_signing_alg: self.request_object_signing_alg.clone(),
589            request_object_encryption_alg: self.request_object_encryption_alg.clone(),
590            request_object_encryption_enc: self.request_object_encryption_enc.clone(),
591            default_max_age: self.default_max_age,
592            require_auth_time: self.require_auth_time,
593            default_acr_values: self.default_acr_values.clone(),
594            initiate_login_uri: self.initiate_login_uri.clone(),
595            request_uris: self.request_uris.clone(),
596            tls_client_certificate_bound_access_tokens: self
597                .tls_client_certificate_bound_access_tokens,
598            post_logout_redirect_uris: self.post_logout_redirect_uris.clone(),
599            authorization_signed_response_alg: self.authorization_signed_response_alg.clone(),
600            authorization_encrypted_response_alg: self.authorization_encrypted_response_alg.clone(),
601            authorization_encrypted_response_enc: self.authorization_encrypted_response_enc.clone(),
602            dpop_bound_access_tokens: self.dpop_bound_access_tokens,
603            other_fields: self.other_fields.clone(),
604        }
605    }
606
607    /// Returs error if JWKS only has private keys
608    pub(crate) fn jwks_only_private_keys_validation(jwks: Option<&Jwks>) -> OidcReturnType<()> {
609        if let Some(jwks) = jwks {
610            if !jwks.is_only_private_keys() || jwks.has_oct_keys() {
611                return Err(Box::new(OidcClientError::new_error(
612                    "jwks must only contain private keys",
613                    None,
614                )));
615            }
616        }
617        Ok(())
618    }
619}
620
621impl Clone for Client {
622    fn clone(&self) -> Self {
623        Self {
624            client_id: self.client_id.clone(),
625            client_secret: self.client_secret.clone(),
626            registration_access_token: self.registration_access_token.clone(),
627            registration_client_uri: self.registration_client_uri.clone(),
628            client_id_issued_at: self.client_id_issued_at,
629            client_secret_expires_at: self.client_secret_expires_at,
630            token_endpoint_auth_method: self.token_endpoint_auth_method.clone(),
631            token_endpoint_auth_signing_alg: self.token_endpoint_auth_signing_alg.clone(),
632            introspection_endpoint_auth_method: self.introspection_endpoint_auth_method.clone(),
633            introspection_endpoint_auth_signing_alg: self
634                .introspection_endpoint_auth_signing_alg
635                .clone(),
636            revocation_endpoint_auth_method: self.revocation_endpoint_auth_method.clone(),
637            revocation_endpoint_auth_signing_alg: self.revocation_endpoint_auth_signing_alg.clone(),
638            redirect_uri: self.redirect_uri.clone(),
639            redirect_uris: self.redirect_uris.clone(),
640            response_type: self.response_type.clone(),
641            response_types: self.response_types.clone(),
642            grant_types: self.grant_types.clone(),
643            jwks_uri: self.jwks_uri.clone(),
644            jwks: self.jwks.clone(),
645            sector_identifier_uri: self.sector_identifier_uri.clone(),
646            subject_type: self.subject_type.clone(),
647            id_token_signed_response_alg: self.id_token_signed_response_alg.clone(),
648            id_token_encrypted_response_alg: self.id_token_encrypted_response_alg.clone(),
649            id_token_encrypted_response_enc: self.id_token_encrypted_response_enc.clone(),
650            userinfo_signed_response_alg: self.userinfo_signed_response_alg.clone(),
651            userinfo_encrypted_response_alg: self.userinfo_encrypted_response_alg.clone(),
652            userinfo_encrypted_response_enc: self.userinfo_encrypted_response_enc.clone(),
653            request_object_signing_alg: self.request_object_signing_alg.clone(),
654            request_object_encryption_alg: self.request_object_encryption_alg.clone(),
655            request_object_encryption_enc: self.request_object_encryption_enc.clone(),
656            default_max_age: self.default_max_age,
657            require_auth_time: self.require_auth_time,
658            default_acr_values: self.default_acr_values.clone(),
659            initiate_login_uri: self.initiate_login_uri.clone(),
660            request_uris: self.request_uris.clone(),
661            tls_client_certificate_bound_access_tokens: self
662                .tls_client_certificate_bound_access_tokens,
663            post_logout_redirect_uris: self.post_logout_redirect_uris.clone(),
664            authorization_encrypted_response_alg: self.authorization_encrypted_response_alg.clone(),
665            authorization_encrypted_response_enc: self.authorization_encrypted_response_enc.clone(),
666            authorization_signed_response_alg: self.authorization_signed_response_alg.clone(),
667            other_fields: self.other_fields.clone(),
668            private_jwks: self.private_jwks.clone(),
669            issuer: self.issuer.clone(),
670            client_options: self.client_options.clone(),
671            skip_max_age_check: self.skip_max_age_check,
672            skip_nonce_check: self.skip_nonce_check,
673            clock_tolerance: self.clock_tolerance,
674            fapi: self.fapi.clone(),
675            now: self.now,
676            dpop_nonce_cache: self.dpop_nonce_cache.clone(),
677            dpop_bound_access_tokens: self.dpop_bound_access_tokens,
678        }
679    }
680}
681
682#[cfg(test)]
683#[path = "../tests/client/mod.rs"]
684mod client_test;