openid_client/issuer/
issuer.rs

1use core::fmt::Debug;
2use std::collections::HashMap;
3
4use crate::client::Client;
5use crate::helpers::{convert_json_to, now, validate_url, webfinger_normalize};
6use crate::http::request_async;
7use crate::jwks::Jwks;
8use crate::types::http_client::HttpMethod;
9use crate::types::{
10    ClientMetadata, ClientOptions, Fapi, HttpRequest, HttpResponse, IssuerMetadata, MtlsEndpoints,
11    OidcClientError, OidcHttpClient, OidcReturnType, WebFingerResponse,
12};
13
14use serde_json::Value;
15use url::Url;
16
17use super::keystore::KeyStore;
18
19/// Holds all the discovered values from the OIDC Issuer
20#[derive(Debug)]
21pub struct Issuer {
22    pub(crate) issuer: String,
23    pub(crate) authorization_endpoint: Option<String>,
24    pub(crate) device_authorization_endpoint: Option<String>,
25    pub(crate) token_endpoint: Option<String>,
26    pub(crate) jwks_uri: Option<String>,
27    pub(crate) userinfo_endpoint: Option<String>,
28    pub(crate) revocation_endpoint: Option<String>,
29    pub(crate) claims_parameter_supported: Option<bool>,
30    pub(crate) grant_types_supported: Option<Vec<String>>,
31    pub(crate) request_parameter_supported: Option<bool>,
32    pub(crate) request_uri_parameter_supported: Option<bool>,
33    pub(crate) require_request_uri_registration: Option<bool>,
34    pub(crate) response_modes_supported: Option<Vec<String>>,
35    pub(crate) claim_types_supported: Vec<String>,
36    pub(crate) token_endpoint_auth_methods_supported: Option<Vec<String>>,
37    pub(crate) token_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
38    pub(crate) introspection_endpoint_auth_methods_supported: Option<Vec<String>>,
39    pub(crate) introspection_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
40    pub(crate) revocation_endpoint_auth_methods_supported: Option<Vec<String>>,
41    pub(crate) revocation_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
42    pub(crate) end_session_endpoint: Option<String>,
43    pub(crate) other_fields: HashMap<String, Value>,
44    pub(crate) keystore: Option<KeyStore>,
45    pub(crate) mtls_endpoint_aliases: Option<MtlsEndpoints>,
46    pub(crate) introspection_endpoint: Option<String>,
47    pub(crate) registration_endpoint: Option<String>,
48    pub(crate) authorization_response_iss_parameter_supported: Option<bool>,
49    pub(crate) dpop_signing_alg_values_supported: Option<Vec<String>>,
50    pub(crate) pushed_authorization_request_endpoint: Option<String>,
51    pub(crate) require_pushed_authorization_requests: bool,
52    pub(crate) backchannel_token_delivery_modes_supported: Option<Vec<String>>,
53    pub(crate) backchannel_authentication_endpoint: Option<String>,
54    pub(crate) backchannel_authentication_request_signing_alg_values_supported: Option<Vec<String>>,
55    pub(crate) backchannel_user_code_parameter_supported: bool,
56    pub(crate) now: fn() -> u64,
57}
58
59impl Default for Issuer {
60    fn default() -> Self {
61        Self {
62            claims_parameter_supported: Some(false),
63            grant_types_supported: Some(vec![
64                String::from("authorization_code"),
65                String::from("implicit"),
66            ]),
67            request_parameter_supported: Some(false),
68            request_uri_parameter_supported: Some(true),
69            require_request_uri_registration: Some(false),
70            response_modes_supported: Some(vec![String::from("query"), String::from("fragment")]),
71            claim_types_supported: vec![String::from("normal")],
72            token_endpoint_auth_methods_supported: Some(vec!["client_secret_basic".to_string()]),
73            introspection_endpoint_auth_methods_supported: None,
74            issuer: "".to_string(),
75            authorization_endpoint: None,
76            token_endpoint: None,
77            jwks_uri: None,
78            userinfo_endpoint: None,
79            revocation_endpoint: None,
80            revocation_endpoint_auth_methods_supported: None,
81            token_endpoint_auth_signing_alg_values_supported: None,
82            introspection_endpoint_auth_signing_alg_values_supported: None,
83            revocation_endpoint_auth_signing_alg_values_supported: None,
84            end_session_endpoint: None,
85            other_fields: Default::default(),
86            keystore: None,
87            mtls_endpoint_aliases: None,
88            introspection_endpoint: None,
89            authorization_response_iss_parameter_supported: None,
90            registration_endpoint: None,
91            dpop_signing_alg_values_supported: None,
92            pushed_authorization_request_endpoint: None,
93            require_pushed_authorization_requests: false,
94            device_authorization_endpoint: None,
95            backchannel_token_delivery_modes_supported: None,
96            backchannel_authentication_endpoint: None,
97            backchannel_authentication_request_signing_alg_values_supported: None,
98            backchannel_user_code_parameter_supported: false,
99            now,
100        }
101    }
102}
103
104/// Issuer Instance Creation
105impl Issuer {
106    fn from(metadata: IssuerMetadata) -> Self {
107        let token_endpoint_auth_methods_supported =
108            match metadata.token_endpoint_auth_methods_supported {
109                None => Some(vec!["client_secret_basic".to_string()]),
110                Some(v) => Some(v),
111            };
112
113        let introspection_endpoint_auth_methods_supported =
114            match metadata.introspection_endpoint_auth_methods_supported {
115                None => token_endpoint_auth_methods_supported.clone(),
116                Some(v) => Some(v),
117            };
118
119        let introspection_endpoint_auth_signing_alg_values_supported =
120            match metadata.introspection_endpoint_auth_signing_alg_values_supported {
121                None => metadata
122                    .token_endpoint_auth_signing_alg_values_supported
123                    .clone(),
124                Some(v) => Some(v),
125            };
126
127        let revocation_endpoint_auth_methods_supported =
128            match metadata.revocation_endpoint_auth_methods_supported {
129                None => token_endpoint_auth_methods_supported.clone(),
130                Some(v) => Some(v),
131            };
132
133        let revocation_endpoint_auth_signing_alg_values_supported =
134            match metadata.revocation_endpoint_auth_signing_alg_values_supported {
135                None => metadata
136                    .token_endpoint_auth_signing_alg_values_supported
137                    .clone(),
138                Some(v) => Some(v),
139            };
140
141        let jwks_uri = metadata.jwks_uri.clone();
142
143        Self {
144            issuer: metadata.issuer,
145            authorization_endpoint: metadata.authorization_endpoint,
146            device_authorization_endpoint: metadata.device_authorization_endpoint,
147            token_endpoint: metadata.token_endpoint,
148            jwks_uri: metadata.jwks_uri,
149            userinfo_endpoint: metadata.userinfo_endpoint,
150            revocation_endpoint: metadata.revocation_endpoint,
151            token_endpoint_auth_methods_supported,
152            introspection_endpoint_auth_methods_supported,
153            introspection_endpoint_auth_signing_alg_values_supported,
154            revocation_endpoint_auth_methods_supported,
155            revocation_endpoint_auth_signing_alg_values_supported,
156            end_session_endpoint: metadata.end_session_endpoint,
157            registration_endpoint: metadata.registration_endpoint,
158            introspection_endpoint: metadata.introspection_endpoint,
159            token_endpoint_auth_signing_alg_values_supported: metadata
160                .token_endpoint_auth_signing_alg_values_supported,
161            mtls_endpoint_aliases: metadata.mtls_endpoint_aliases,
162            authorization_response_iss_parameter_supported: metadata
163                .authorization_response_iss_parameter_supported,
164            dpop_signing_alg_values_supported: metadata.dpop_signing_alg_values_supported,
165            pushed_authorization_request_endpoint: metadata.pushed_authorization_request_endpoint,
166            require_pushed_authorization_requests: metadata.require_pushed_authorization_requests,
167            other_fields: metadata.other_fields,
168            keystore: Some(KeyStore::new(jwks_uri)),
169            backchannel_token_delivery_modes_supported: metadata
170                .backchannel_token_delivery_modes_supported,
171            backchannel_authentication_endpoint: metadata.backchannel_authentication_endpoint,
172            backchannel_authentication_request_signing_alg_values_supported: metadata
173                .backchannel_authentication_request_signing_alg_values_supported,
174            backchannel_user_code_parameter_supported: metadata
175                .backchannel_user_code_parameter_supported
176                .unwrap_or(false),
177            ..Issuer::default()
178        }
179    }
180
181    /// ## Issuer
182    ///
183    /// Create an [Issuer] instance using [IssuerMetadata].
184    ///
185    /// - `metadata` - [IssuerMetadata]
186    ///
187    /// No OIDC Discovery defaults are set if Issuer is created using this method.
188    ///
189    /// If no introspection/revocation endpoint auth methods or algorithms are specified,
190    /// value of token endpoint auth methods and algorithms are used as the the value for the said
191    /// properties.
192    pub fn new(metadata: IssuerMetadata) -> Self {
193        let introspection_endpoint_auth_methods_supported =
194            match metadata.introspection_endpoint_auth_methods_supported {
195                None => metadata.token_endpoint_auth_methods_supported.clone(),
196                Some(v) => Some(v),
197            };
198
199        let introspection_endpoint_auth_signing_alg_values_supported =
200            match metadata.introspection_endpoint_auth_signing_alg_values_supported {
201                None => metadata
202                    .token_endpoint_auth_signing_alg_values_supported
203                    .clone(),
204                Some(v) => Some(v),
205            };
206
207        let revocation_endpoint_auth_methods_supported =
208            match metadata.revocation_endpoint_auth_methods_supported {
209                None => metadata.token_endpoint_auth_methods_supported.clone(),
210                Some(v) => Some(v),
211            };
212
213        let revocation_endpoint_auth_signing_alg_values_supported =
214            match metadata.revocation_endpoint_auth_signing_alg_values_supported {
215                None => metadata
216                    .token_endpoint_auth_signing_alg_values_supported
217                    .clone(),
218                Some(v) => Some(v),
219            };
220
221        let jwks_uri = metadata.jwks_uri.clone();
222
223        Self {
224            issuer: metadata.issuer,
225            authorization_endpoint: metadata.authorization_endpoint,
226            token_endpoint: metadata.token_endpoint,
227            jwks_uri: metadata.jwks_uri,
228            userinfo_endpoint: metadata.userinfo_endpoint,
229            revocation_endpoint: metadata.revocation_endpoint,
230            claims_parameter_supported: None,
231            grant_types_supported: None,
232            request_parameter_supported: None,
233            request_uri_parameter_supported: None,
234            require_request_uri_registration: None,
235            response_modes_supported: None,
236            claim_types_supported: vec![],
237            token_endpoint_auth_methods_supported: metadata.token_endpoint_auth_methods_supported,
238            introspection_endpoint_auth_methods_supported,
239            token_endpoint_auth_signing_alg_values_supported: metadata
240                .token_endpoint_auth_signing_alg_values_supported,
241            introspection_endpoint_auth_signing_alg_values_supported,
242            revocation_endpoint_auth_methods_supported,
243            revocation_endpoint_auth_signing_alg_values_supported,
244            other_fields: metadata.other_fields,
245            keystore: Some(KeyStore::new(jwks_uri)),
246            mtls_endpoint_aliases: metadata.mtls_endpoint_aliases,
247            introspection_endpoint: metadata.introspection_endpoint,
248            registration_endpoint: metadata.registration_endpoint,
249            end_session_endpoint: metadata.end_session_endpoint,
250            authorization_response_iss_parameter_supported: metadata
251                .authorization_response_iss_parameter_supported,
252            dpop_signing_alg_values_supported: metadata.dpop_signing_alg_values_supported,
253            pushed_authorization_request_endpoint: metadata.pushed_authorization_request_endpoint,
254            require_pushed_authorization_requests: metadata.require_pushed_authorization_requests,
255            device_authorization_endpoint: metadata.device_authorization_endpoint,
256            backchannel_token_delivery_modes_supported: metadata
257                .backchannel_token_delivery_modes_supported,
258            backchannel_authentication_endpoint: metadata.backchannel_authentication_endpoint,
259            backchannel_authentication_request_signing_alg_values_supported: metadata
260                .backchannel_authentication_request_signing_alg_values_supported,
261            backchannel_user_code_parameter_supported: metadata
262                .backchannel_user_code_parameter_supported
263                .unwrap_or(false),
264            now,
265        }
266    }
267}
268
269/// OIDC [Issuer Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery)
270impl Issuer {
271    /// # Discover OIDC Issuer
272    ///
273    /// Discover an OIDC Issuer using the issuer url.
274    ///
275    /// - `http_client` - The http client used to make the request.
276    /// - `issuer` - The issuer url (absolute).
277    ///
278    /// *Only an absolute urls are accepted, passing in `auth.example.com` will result in an error.*
279    pub async fn discover_async<T>(http_client: &T, issuer: &str) -> OidcReturnType<Issuer>
280    where
281        T: OidcHttpClient,
282    {
283        let mut url = match validate_url(issuer) {
284            Ok(parsed) => parsed,
285            Err(err) => return Err(err),
286        };
287
288        let mut path: String = url.path().to_string();
289        if path.ends_with('/') {
290            path.pop();
291        }
292
293        if path.ends_with(".well-known") {
294            path.push_str("/openid-configuration");
295        } else if !path.contains(".well-known") {
296            path.push_str("/.well-known/openid-configuration");
297        }
298
299        url.set_path(&path);
300
301        let mut headers = HashMap::new();
302        headers.insert("accept".to_string(), vec!["application/json".to_string()]);
303
304        let req = HttpRequest::new().url(url).headers(headers);
305
306        let res = request_async(req, http_client).await?;
307
308        let issuer_metadata = match convert_json_to::<IssuerMetadata>(res.body.as_ref().unwrap()) {
309            Ok(metadata) => metadata,
310            Err(_) => {
311                return Err(Box::new(OidcClientError::new_op_error(
312                    "invalid_issuer_metadata".to_string(),
313                    None,
314                    None,
315                    Some(res),
316                )));
317            }
318        };
319
320        Ok(Issuer::from(issuer_metadata))
321    }
322}
323
324/// OIDC [Issuer Webfinger Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery)
325impl Issuer {
326    /// # Webfinger OIDC Issuer Discovery
327    ///
328    /// Discover an OIDC Issuer using the user email, url, url with port syntax or acct syntax.
329    ///
330    /// - `http_client` - The http client to make the request
331    /// - `input` - The resource.
332    ///
333    pub async fn webfinger_async<T>(http_client: &T, input: &str) -> OidcReturnType<Issuer>
334    where
335        T: OidcHttpClient,
336    {
337        let req = Self::build_webfinger_request(input)?;
338
339        let res = request_async(req, http_client).await?;
340
341        let expected_issuer = Self::process_webfinger_response(res)?;
342
343        let issuer_result = Issuer::discover_async(http_client, &expected_issuer).await;
344
345        Self::process_webfinger_issuer_result(issuer_result, expected_issuer)
346    }
347
348    fn build_webfinger_request(input: &str) -> OidcReturnType<HttpRequest> {
349        let resource = webfinger_normalize(input);
350
351        let mut host: Option<String> = None;
352
353        if resource.starts_with("acct:") {
354            let split: Vec<&str> = resource.split('@').collect();
355            host = split.last().map(|s| s.to_string());
356        } else if resource.starts_with("https://") {
357            let url = validate_url(&resource)?;
358
359            if let Some(host_str) = url.host_str() {
360                host = match url.port() {
361                    Some(port) => Some(host_str.to_string() + &format!(":{port}")),
362                    None => Some(host_str.to_string()),
363                }
364            }
365        }
366
367        if host.is_none() {
368            return Err(Box::new(OidcClientError::new_type_error(
369                "given input was invalid",
370                None,
371            )));
372        }
373
374        let mut web_finger_url =
375            Url::parse(&format!("https://{}/.well-known/webfinger", host.unwrap())).unwrap();
376
377        let mut headers = HashMap::new();
378        headers.insert("accept".to_string(), vec!["application/json".to_string()]);
379
380        web_finger_url.set_query(Some(&format!(
381            "resource={}&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer",
382            urlencoding::encode(&resource)
383        )));
384
385        Ok(HttpRequest::new()
386            .url(web_finger_url)
387            .method(HttpMethod::GET)
388            .headers(headers)
389            .expect_bearer(false)
390            .expect_status_code(200)
391            .expect_body(true))
392    }
393
394    fn process_webfinger_response(response: HttpResponse) -> OidcReturnType<String> {
395        let webfinger_response =
396            match convert_json_to::<WebFingerResponse>(response.body.as_ref().unwrap()) {
397                Ok(res) => res,
398                Err(_) => {
399                    return Err(Box::new(OidcClientError::new_op_error(
400                        "invalid  webfinger response".to_string(),
401                        None,
402                        None,
403                        Some(response),
404                    )));
405                }
406            };
407
408        let location_link_result = webfinger_response
409            .links
410            .iter()
411            .find(|x| x.rel == "http://openid.net/specs/connect/1.0/issuer" && x.href.is_some());
412
413        let expected_issuer = match location_link_result {
414            Some(link) => link.href.as_ref().unwrap(),
415            None => {
416                return Err(Box::new(OidcClientError::new_rp_error(
417                    "no issuer found in webfinger response",
418                    Some(response),
419                )));
420            }
421        };
422
423        if !expected_issuer.starts_with("https://") {
424            return Err(Box::new(OidcClientError::new_op_error(
425                "invalid_location".to_string(),
426                Some(format!("invalid issuer location {expected_issuer}")),
427                None,
428                Some(response),
429            )));
430        }
431
432        Ok(expected_issuer.to_string())
433    }
434
435    fn process_webfinger_issuer_result(
436        issuer_result: OidcReturnType<Issuer>,
437        expected_issuer: String,
438    ) -> OidcReturnType<Issuer> {
439        let mut response = None;
440
441        let issuer = match issuer_result {
442            Ok(i) => i,
443            Err(err) => {
444                response = match err.as_ref() {
445                    OidcClientError::Error(_, response) => response.as_ref(),
446                    OidcClientError::TypeError(_, response) => response.as_ref(),
447                    OidcClientError::RPError(_, response) => response.as_ref(),
448                    OidcClientError::OPError(_, response) => response.as_ref(),
449                };
450
451                if let Some(error_res) = response {
452                    if error_res.status_code == 404 {
453                        return Err(Box::new(OidcClientError::new_op_error(
454                            "no_issuer".to_string(),
455                            Some(format!("invalid issuer location {expected_issuer}")),
456                            None,
457                            Some(error_res.clone()),
458                        )));
459                    }
460                }
461
462                return Err(err);
463            }
464        };
465
466        if issuer.issuer != expected_issuer {
467            return Err(Box::new(OidcClientError::new_op_error(
468                "issuer_mismatch".to_string(),
469                Some(format!(
470                    "discovered issuer mismatch, expected {expected_issuer}, got: {}",
471                    issuer.issuer
472                )),
473                None,
474                response.map(|r| r.to_owned()),
475            )));
476        }
477
478        Ok(issuer)
479    }
480}
481
482/// New [Client] implementation for Issuer
483impl Issuer {
484    /// # Creates a client from the issuer
485    /// This method creates a new [Client] from the issuer.
486    /// A client metadata with a required `client_id` field is also required
487    ///
488    /// - `metadata` - [ClientMetadata]
489    /// - `jwks` - The client jwks with private keys.
490    /// - `client_options` - Client options.
491    /// - `fapi` - Version of FAPI
492    ///
493    /// Note: If the [Issuer] already have a request interceptor and none was passed in through `interceptor`,
494    ///       the interceptor from the [Issuer] is used.
495    pub fn client(
496        &self,
497        metadata: ClientMetadata,
498        jwks: Option<Jwks>,
499        client_options: Option<ClientOptions>,
500        fapi: Option<Fapi>,
501    ) -> OidcReturnType<Client> {
502        Client::jwks_only_private_keys_validation(jwks.as_ref())?;
503
504        Client::from_internal(metadata, Some(self), jwks, client_options, fapi)
505    }
506}
507
508impl Clone for Issuer {
509    fn clone(&self) -> Self {
510        Self {
511            issuer: self.issuer.clone(),
512            authorization_endpoint: self.authorization_endpoint.clone(),
513            token_endpoint: self.token_endpoint.clone(),
514            jwks_uri: self.jwks_uri.clone(),
515            userinfo_endpoint: self.userinfo_endpoint.clone(),
516            revocation_endpoint: self.revocation_endpoint.clone(),
517            claims_parameter_supported: self.claims_parameter_supported,
518            grant_types_supported: self.grant_types_supported.clone(),
519            request_parameter_supported: self.request_parameter_supported,
520            request_uri_parameter_supported: self.request_uri_parameter_supported,
521            require_request_uri_registration: self.require_request_uri_registration,
522            response_modes_supported: self.response_modes_supported.clone(),
523            claim_types_supported: self.claim_types_supported.clone(),
524            token_endpoint_auth_methods_supported: self
525                .token_endpoint_auth_methods_supported
526                .clone(),
527            token_endpoint_auth_signing_alg_values_supported: self
528                .token_endpoint_auth_signing_alg_values_supported
529                .clone(),
530            introspection_endpoint_auth_methods_supported: self
531                .introspection_endpoint_auth_methods_supported
532                .clone(),
533            introspection_endpoint_auth_signing_alg_values_supported: self
534                .introspection_endpoint_auth_signing_alg_values_supported
535                .clone(),
536            revocation_endpoint_auth_methods_supported: self
537                .revocation_endpoint_auth_methods_supported
538                .clone(),
539            revocation_endpoint_auth_signing_alg_values_supported: self
540                .revocation_endpoint_auth_signing_alg_values_supported
541                .clone(),
542            other_fields: self.other_fields.clone(),
543            keystore: self.keystore.clone(),
544            mtls_endpoint_aliases: self.mtls_endpoint_aliases.clone(),
545            introspection_endpoint: self.introspection_endpoint.clone(),
546            registration_endpoint: self.registration_endpoint.clone(),
547            end_session_endpoint: self.end_session_endpoint.clone(),
548            authorization_response_iss_parameter_supported: self
549                .authorization_response_iss_parameter_supported,
550            dpop_signing_alg_values_supported: self.dpop_signing_alg_values_supported.clone(),
551            pushed_authorization_request_endpoint: self
552                .pushed_authorization_request_endpoint
553                .clone(),
554            require_pushed_authorization_requests: self.require_pushed_authorization_requests,
555            device_authorization_endpoint: self.device_authorization_endpoint.clone(),
556            backchannel_token_delivery_modes_supported: self
557                .backchannel_token_delivery_modes_supported
558                .clone(),
559            backchannel_authentication_endpoint: self.backchannel_authentication_endpoint.clone(),
560            backchannel_authentication_request_signing_alg_values_supported: self
561                .backchannel_authentication_request_signing_alg_values_supported
562                .clone(),
563            backchannel_user_code_parameter_supported: self
564                .backchannel_user_code_parameter_supported,
565            now,
566        }
567    }
568}
569
570impl Issuer {
571    /// Gets the [IssuerMetadata] of the [Issuer]
572    pub fn get_metadata(&self) -> IssuerMetadata {
573        IssuerMetadata {
574            issuer: self.issuer.clone(),
575            authorization_endpoint: self.authorization_endpoint.clone(),
576            device_authorization_endpoint: self.device_authorization_endpoint.clone(),
577            token_endpoint: self.token_endpoint.clone(),
578            jwks_uri: self.jwks_uri.clone(),
579            userinfo_endpoint: self.userinfo_endpoint.clone(),
580            revocation_endpoint: self.revocation_endpoint.clone(),
581            end_session_endpoint: self.end_session_endpoint.clone(),
582            registration_endpoint: self.registration_endpoint.clone(),
583            introspection_endpoint: self.introspection_endpoint.clone(),
584            token_endpoint_auth_methods_supported: self
585                .token_endpoint_auth_methods_supported
586                .clone(),
587            token_endpoint_auth_signing_alg_values_supported: self
588                .token_endpoint_auth_signing_alg_values_supported
589                .clone(),
590            introspection_endpoint_auth_methods_supported: self
591                .introspection_endpoint_auth_methods_supported
592                .clone(),
593            introspection_endpoint_auth_signing_alg_values_supported: self
594                .introspection_endpoint_auth_signing_alg_values_supported
595                .clone(),
596            revocation_endpoint_auth_methods_supported: self
597                .revocation_endpoint_auth_methods_supported
598                .clone(),
599            revocation_endpoint_auth_signing_alg_values_supported: self
600                .revocation_endpoint_auth_signing_alg_values_supported
601                .clone(),
602            mtls_endpoint_aliases: self.mtls_endpoint_aliases.clone(),
603            authorization_response_iss_parameter_supported: self
604                .authorization_response_iss_parameter_supported,
605            dpop_signing_alg_values_supported: self.dpop_signing_alg_values_supported.clone(),
606            pushed_authorization_request_endpoint: self
607                .pushed_authorization_request_endpoint
608                .clone(),
609            require_pushed_authorization_requests: self.require_pushed_authorization_requests,
610            backchannel_token_delivery_modes_supported: self
611                .backchannel_token_delivery_modes_supported
612                .clone(),
613            backchannel_authentication_endpoint: self.backchannel_authentication_endpoint.clone(),
614            backchannel_authentication_request_signing_alg_values_supported: self
615                .backchannel_authentication_request_signing_alg_values_supported
616                .clone(),
617            backchannel_user_code_parameter_supported: Some(
618                self.backchannel_user_code_parameter_supported,
619            ),
620            other_fields: self.other_fields.clone(),
621        }
622    }
623
624    /// Get Jwks
625    pub async fn get_jwks<T>(&mut self, http_client: &T) -> Option<Jwks>
626    where
627        T: OidcHttpClient,
628    {
629        if let Some(ks) = &mut self.keystore {
630            return ks.get_keystore_async(false, http_client).await.ok();
631        }
632
633        None
634    }
635}
636
637#[cfg(test)]
638#[path = "../tests/issuer/mod.rs"]
639mod issuer_tests;