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}