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