use mas_http::{CatchHttpCodesLayer, JsonRequestLayer, JsonResponseLayer};
use mas_iana::oauth::OAuthClientAuthenticationMethod;
use oauth2_types::registration::{ClientRegistrationResponse, VerifiedClientMetadata};
use serde::Serialize;
use serde_with::skip_serializing_none;
use tower::{Layer, Service, ServiceExt};
use url::Url;
use crate::{
error::RegistrationError,
http_service::HttpService,
utils::{http_all_error_status_codes, http_error_mapper},
};
#[skip_serializing_none]
#[derive(Serialize)]
struct RegistrationRequest {
#[serde(flatten)]
client_metadata: VerifiedClientMetadata,
software_statement: Option<String>,
}
#[tracing::instrument(skip_all, fields(registration_endpoint))]
pub async fn register_client(
http_service: &HttpService,
registration_endpoint: &Url,
client_metadata: VerifiedClientMetadata,
software_statement: Option<String>,
) -> Result<ClientRegistrationResponse, RegistrationError> {
tracing::debug!("Registering client...");
let should_receive_secret = matches!(
client_metadata.token_endpoint_auth_method(),
OAuthClientAuthenticationMethod::ClientSecretPost
| OAuthClientAuthenticationMethod::ClientSecretBasic
| OAuthClientAuthenticationMethod::ClientSecretJwt
);
let body = RegistrationRequest {
client_metadata,
software_statement,
};
let registration_req = http::Request::post(registration_endpoint.as_str()).body(body)?;
let service = (
JsonRequestLayer::default(),
JsonResponseLayer::<ClientRegistrationResponse>::default(),
CatchHttpCodesLayer::new(http_all_error_status_codes(), http_error_mapper),
)
.layer(http_service.clone());
let response = service
.ready_oneshot()
.await?
.call(registration_req)
.await?
.into_body();
if should_receive_secret && response.client_secret.is_none() {
return Err(RegistrationError::MissingClientSecret);
}
Ok(response)
}