use crate::config::OnesOidcConfig;
use crate::errors::DiscoveryError;
use log::{debug, info, warn};
use openidconnect::core::CoreProviderMetadata;
use openidconnect::reqwest::async_http_client;
use openidconnect::IssuerUrl;
use std::time::Duration;
use tokio::time::sleep;
pub async fn discover_provider_metadata(
issuer_url: &IssuerUrl,
config: &OnesOidcConfig,
) -> Result<CoreProviderMetadata, DiscoveryError> {
let max_attempts = config.max_discovery_retries + 1; let mut current_backoff = config.discovery_backoff;
let mut last_error = String::new();
for attempt in 1..=max_attempts {
debug!(
"OIDC discovery attempt {}/{} for {}",
attempt,
max_attempts,
issuer_url.as_str()
);
match CoreProviderMetadata::discover_async(issuer_url.clone(), async_http_client).await {
Ok(metadata) => {
if attempt > 1 {
info!(
"OIDC discovery succeeded on attempt {} for {}",
attempt,
issuer_url.as_str()
);
}
return Ok(metadata);
}
Err(e) => {
last_error = e.to_string();
if attempt < max_attempts {
warn!(
"OIDC discovery attempt {}/{} failed: {}. Retrying in {:?}...",
attempt, max_attempts, last_error, current_backoff
);
sleep(current_backoff).await;
current_backoff = Duration::from_secs(
(current_backoff.as_secs() * 2).min(60), );
}
}
}
}
Err(DiscoveryError::DiscoveryFailed {
attempts: max_attempts,
message: last_error,
})
}
pub async fn discover_provider_metadata_from_str(
issuer_url_str: &str,
config: &OnesOidcConfig,
) -> Result<CoreProviderMetadata, DiscoveryError> {
let issuer_url = IssuerUrl::new(issuer_url_str.to_string())
.map_err(|e| DiscoveryError::InvalidIssuerUrl(e.to_string()))?;
discover_provider_metadata(&issuer_url, config).await
}