mas_oidc_client/requests/discovery.rs
1// Copyright 2024 New Vector Ltd.
2// Copyright 2022-2024 Kévin Commaille.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7//! Requests for OpenID Connect Provider [Discovery].
8//!
9//! [Discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
10
11use mas_http::RequestBuilderExt;
12use oauth2_types::oidc::{ProviderMetadata, VerifiedProviderMetadata};
13use url::Url;
14
15use crate::error::DiscoveryError;
16
17/// Fetch the provider metadata.
18async fn discover_inner(
19 client: &reqwest::Client,
20 issuer: Url,
21) -> Result<ProviderMetadata, DiscoveryError> {
22 tracing::debug!("Fetching provider metadata...");
23
24 let mut config_url = issuer;
25
26 // If the path doesn't end with a slash, the last segment is removed when
27 // using `join`.
28 if !config_url.path().ends_with('/') {
29 let mut path = config_url.path().to_owned();
30 path.push('/');
31 config_url.set_path(&path);
32 }
33
34 let config_url = config_url.join(".well-known/openid-configuration")?;
35
36 let response = client
37 .get(config_url.as_str())
38 .send_traced()
39 .await?
40 .error_for_status()?
41 .json()
42 .await?;
43
44 tracing::debug!(?response);
45
46 Ok(response)
47}
48
49/// Fetch the provider metadata and validate it.
50///
51/// # Errors
52///
53/// Returns an error if the request fails or if the data is invalid.
54#[tracing::instrument(skip_all, fields(issuer))]
55pub async fn discover(
56 client: &reqwest::Client,
57 issuer: &str,
58) -> Result<VerifiedProviderMetadata, DiscoveryError> {
59 let provider_metadata = discover_inner(client, issuer.parse()?).await?;
60
61 Ok(provider_metadata.validate(issuer)?)
62}
63
64/// Fetch the [provider metadata] and make basic checks.
65///
66/// Contrary to [`discover()`], this uses
67/// [`ProviderMetadata::insecure_verify_metadata()`] to check the received
68/// metadata instead of validating it according to the specification.
69///
70/// # Arguments
71///
72/// * `http_client` - The reqwest client to use for making HTTP requests.
73///
74/// * `issuer` - The URL of the OpenID Connect Provider to fetch metadata for.
75///
76/// # Errors
77///
78/// Returns an error if the request fails or if the data is invalid.
79///
80/// # Warning
81///
82/// It is not recommended to use this method in production as it doesn't
83/// ensure that the issuer implements the proper security practices.
84///
85/// [provider metadata]: https://openid.net/specs/openid-connect-discovery-1_0.html
86#[tracing::instrument(skip_all, fields(issuer))]
87pub async fn insecure_discover(
88 client: &reqwest::Client,
89 issuer: &str,
90) -> Result<VerifiedProviderMetadata, DiscoveryError> {
91 let provider_metadata = discover_inner(client, issuer.parse()?).await?;
92
93 Ok(provider_metadata.insecure_verify_metadata()?)
94}