use authkestra_core::{AuthError, OAuthToken};
pub struct ClientCredentialsFlow {
client_id: String,
client_secret: String,
token_url: String,
http_client: reqwest::Client,
}
impl ClientCredentialsFlow {
pub fn new(client_id: String, client_secret: String, token_url: String) -> Self {
Self {
client_id,
client_secret,
token_url,
http_client: reqwest::Client::new(),
}
}
pub async fn get_token(&self, scopes: Option<&[&str]>) -> Result<OAuthToken, AuthError> {
let mut params = vec![
("grant_type", "client_credentials"),
("client_id", &self.client_id),
("client_secret", &self.client_secret),
];
let scope_str;
if let Some(s) = scopes {
scope_str = s.join(" ");
params.push(("scope", &scope_str));
}
let response = self
.http_client
.post(&self.token_url)
.header("Accept", "application/json")
.form(¶ms)
.send()
.await
.map_err(|_| AuthError::Network)?;
if !response.status().is_success() {
let error_text = response.text().await.unwrap_or_default();
return Err(AuthError::Provider(format!(
"Token request failed: {}",
error_text
)));
}
response
.json::<OAuthToken>()
.await
.map_err(|e| AuthError::Provider(format!("Failed to parse token response: {}", e)))
}
}