authly_flow/
client_credentials_flow.rs1use authly_core::{AuthError, OAuthToken};
2
3pub struct ClientCredentialsFlow {
8 client_id: String,
9 client_secret: String,
10 token_url: String,
11 http_client: reqwest::Client,
12}
13
14impl ClientCredentialsFlow {
15 pub fn new(client_id: String, client_secret: String, token_url: String) -> Self {
23 Self {
24 client_id,
25 client_secret,
26 token_url,
27 http_client: reqwest::Client::new(),
28 }
29 }
30
31 pub async fn get_token(&self, scopes: Option<&[&str]>) -> Result<OAuthToken, AuthError> {
41 let mut params = vec![
42 ("grant_type", "client_credentials"),
43 ("client_id", &self.client_id),
44 ("client_secret", &self.client_secret),
45 ];
46
47 let scope_str;
48 if let Some(s) = scopes {
49 scope_str = s.join(" ");
50 params.push(("scope", &scope_str));
51 }
52
53 let response = self
54 .http_client
55 .post(&self.token_url)
56 .header("Accept", "application/json")
57 .form(¶ms)
58 .send()
59 .await
60 .map_err(|_| AuthError::Network)?;
61
62 if !response.status().is_success() {
63 let error_text = response.text().await.unwrap_or_default();
64 return Err(AuthError::Provider(format!(
65 "Token request failed: {}",
66 error_text
67 )));
68 }
69
70 response
71 .json::<OAuthToken>()
72 .await
73 .map_err(|e| AuthError::Provider(format!("Failed to parse token response: {}", e)))
74 }
75}