mod client_secret;
mod form_value;
mod jwt_bearer;
mod no_auth;
use std::sync::Arc;
use bon::Builder;
pub use client_secret::{ClientSecret, ClientSecretBuilder};
pub use form_value::FormValue;
use http::HeaderMap;
pub use jwt_bearer::{Audience, JwtBearer, JwtBearerBuilder, MissingIssuer, MissingTokenEndpoint};
pub use no_auth::NoAuth;
use crate::{
EndpointUrl,
error::Error,
platform::{MaybeSendBoxFuture, MaybeSendSync},
};
pub trait ClientAuthentication: MaybeSendSync {
fn authentication_params<'a>(
&'a self,
client_id: &'a str,
issuer: Option<&'a str>,
token_endpoint: Option<&'a EndpointUrl>,
target_endpoint: &'a EndpointUrl,
allowed_methods: Option<&'a [String]>,
) -> MaybeSendBoxFuture<'a, Result<AuthenticationParams<'a>, Error>>;
}
impl<T: ClientAuthentication + ?Sized> ClientAuthentication for &T {
fn authentication_params<'a>(
&'a self,
client_id: &'a str,
issuer: Option<&'a str>,
token_endpoint: Option<&'a EndpointUrl>,
target_endpoint: &'a EndpointUrl,
allowed_methods: Option<&'a [String]>,
) -> MaybeSendBoxFuture<'a, Result<AuthenticationParams<'a>, Error>> {
(**self).authentication_params(
client_id,
issuer,
token_endpoint,
target_endpoint,
allowed_methods,
)
}
}
impl<T: ClientAuthentication + ?Sized> ClientAuthentication for Box<T> {
fn authentication_params<'a>(
&'a self,
client_id: &'a str,
issuer: Option<&'a str>,
token_endpoint: Option<&'a EndpointUrl>,
target_endpoint: &'a EndpointUrl,
allowed_methods: Option<&'a [String]>,
) -> MaybeSendBoxFuture<'a, Result<AuthenticationParams<'a>, Error>> {
(**self).authentication_params(
client_id,
issuer,
token_endpoint,
target_endpoint,
allowed_methods,
)
}
}
impl<T: ClientAuthentication + ?Sized> ClientAuthentication for Arc<T> {
fn authentication_params<'a>(
&'a self,
client_id: &'a str,
issuer: Option<&'a str>,
token_endpoint: Option<&'a EndpointUrl>,
target_endpoint: &'a EndpointUrl,
allowed_methods: Option<&'a [String]>,
) -> MaybeSendBoxFuture<'a, Result<AuthenticationParams<'a>, Error>> {
(**self).authentication_params(
client_id,
issuer,
token_endpoint,
target_endpoint,
allowed_methods,
)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Builder)]
pub struct AuthenticationParams<'a> {
pub headers: Option<HeaderMap>,
pub form_params: Option<Vec<(&'static str, FormValue<'a>)>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn erased_authentication_dispatches() {
let auth: Arc<dyn ClientAuthentication> = Arc::new(NoAuth);
let uri: EndpointUrl = "https://as.example/token".parse().unwrap();
let params = auth
.authentication_params("my-client", None, Some(&uri), &uri, None)
.await
.expect("no_auth never fails");
let form = params.form_params.expect("client_id form param");
assert!(form.iter().any(|(k, _)| *k == "client_id"));
}
}