1use mkt_core::error::{MktError, Result};
4use secrecy::SecretString;
5
6pub const GOOGLE_TOKEN_URL: &str = "https://oauth2.googleapis.com/token";
8
9pub async fn fetch_access_token(
20 client_id: &str,
21 client_secret: &str,
22 refresh_token: &str,
23 token_url: &str,
24) -> Result<SecretString> {
25 let http = mkt_core::http::build_http_client(None)?;
26 let params = [
27 ("grant_type", "refresh_token"),
28 ("client_id", client_id),
29 ("client_secret", client_secret),
30 ("refresh_token", refresh_token),
31 ];
32
33 let response = http.post(token_url).form(¶ms).send().await?;
34 let status = response.status().as_u16();
35 let body: serde_json::Value = response.json().await?;
36
37 if !(200..300).contains(&status) {
38 let detail = body["error_description"]
39 .as_str()
40 .or_else(|| body["error"].as_str())
41 .unwrap_or("token endpoint returned an error");
42 return Err(MktError::auth_error(
43 "google",
44 &format!("OAuth refresh failed ({status}): {detail}"),
45 ));
46 }
47
48 body["access_token"].as_str().map_or_else(
49 || {
50 Err(MktError::auth_error(
51 "google",
52 "token endpoint response missing 'access_token'",
53 ))
54 },
55 |token| Ok(SecretString::new(token.to_string().into())),
56 )
57}