1// Copyright 2025 Kévin Commaille
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
1415//! Requests for [OpenID Connect Provider Discovery].
16//!
17//! [OpenID Connect Provider Discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
1819use oauth2::{AsyncHttpClient, HttpClientError, RequestTokenError};
20use ruma::{
21 api::client::discovery::get_authorization_server_metadata::msc2965::AuthorizationServerMetadata,
22 serde::Raw,
23};
24use url::Url;
2526use super::{
27 error::OAuthDiscoveryError,
28 http_client::{check_http_response_json_content_type, check_http_response_status_code},
29 OAuthHttpClient,
30};
3132/// Fetch the OpenID Connect provider metadata.
33pub(super) async fn discover(
34 http_client: &OAuthHttpClient,
35 issuer: &str,
36) -> Result<Raw<AuthorizationServerMetadata>, OAuthDiscoveryError> {
37tracing::debug!("Fetching OpenID Connect provider metadata...");
3839let mut url = Url::parse(issuer)?;
4041// If the path doesn't end with a slash, the last segment is removed when
42 // using `join`.
43if !url.path().ends_with('/') {
44let mut path = url.path().to_owned();
45 path.push('/');
46 url.set_path(&path);
47 }
4849let config_url = url.join(".well-known/openid-configuration")?;
5051let request = http::Request::get(config_url.as_str())
52 .body(Vec::new())
53 .map_err(|err| RequestTokenError::Request(HttpClientError::Http(err)))?;
54let response = http_client.call(request).await.map_err(RequestTokenError::Request)?;
5556 check_http_response_status_code(&response)?;
57 check_http_response_json_content_type(&response)?;
5859let metadata = serde_json::from_slice(&response.into_body())?;
6061tracing::debug!(?metadata);
6263Ok(metadata)
64}