use language_tags::LanguageTag;
use oauth2_types::oidc::RpInitiatedLogoutRequest;
use rand::{
distributions::{Alphanumeric, DistString},
Rng,
};
use url::Url;
#[derive(Default, Clone)]
pub struct LogoutData {
pub id_token_hint: Option<String>,
pub logout_hint: Option<String>,
pub client_id: Option<String>,
pub post_logout_redirect_uri: Option<Url>,
pub ui_locales: Option<Vec<LanguageTag>>,
}
pub fn build_end_session_url(
mut end_session_endpoint: Url,
logout_data: LogoutData,
rng: &mut impl Rng,
) -> Result<(Url, Option<String>), serde_urlencoded::ser::Error> {
let LogoutData {
id_token_hint,
logout_hint,
client_id,
post_logout_redirect_uri,
ui_locales,
} = logout_data;
let state = if post_logout_redirect_uri.is_some() {
Some(Alphanumeric.sample_string(rng, 16))
} else {
None
};
let logout_request = RpInitiatedLogoutRequest {
id_token_hint,
logout_hint,
client_id,
post_logout_redirect_uri,
state: state.clone(),
ui_locales,
};
let logout_query = serde_urlencoded::to_string(logout_request)?;
let mut full_query = end_session_endpoint
.query()
.map(ToOwned::to_owned)
.unwrap_or_default();
if !full_query.is_empty() {
full_query.push('&');
}
full_query.push_str(&logout_query);
end_session_endpoint.set_query(Some(&full_query));
Ok((end_session_endpoint, state))
}