1use gog_auth::Service;
6use gog_core::config;
7use crate::error::ApiError;
8
9const TOKEN_ENDPOINT: &str = "https://oauth2.googleapis.com/token";
10
11pub struct AuthenticatedClient {
13 pub client: reqwest::Client,
14 pub access_token: String,
15 pub email: String,
16}
17
18impl AuthenticatedClient {
19 pub async fn new(
27 service: Service,
28 email: &str,
29 oauth_client: &str,
30 ) -> Result<Self, ApiError> {
31 let creds = config::read_client_credentials_for(oauth_client)?;
33
34 let store = gog_secrets::open_store()?;
36 let token = store.get_token(oauth_client, email)?;
37 let refresh_token = token.refresh_token;
38
39 let scopes = service.scopes().join(" ");
41 let http_client = reqwest::Client::new();
42 let params = [
43 ("client_id", creds.client_id.as_str()),
44 ("client_secret", creds.client_secret.as_str()),
45 ("refresh_token", refresh_token.as_str()),
46 ("grant_type", "refresh_token"),
47 ("scope", scopes.as_str()),
48 ];
49
50 let resp = http_client
51 .post(TOKEN_ENDPOINT)
52 .form(¶ms)
53 .send()
54 .await?;
55
56 if !resp.status().is_success() {
57 let status = resp.status().as_u16();
58 let msg = resp.text().await.unwrap_or_default();
59 return Err(ApiError::GoogleApi {
60 status,
61 message: msg,
62 });
63 }
64
65 let token_resp: serde_json::Value = resp.json().await?;
66 let access_token = token_resp["access_token"]
67 .as_str()
68 .ok_or_else(|| ApiError::GoogleApi {
69 status: 0,
70 message: "missing access_token in response".to_string(),
71 })?
72 .to_string();
73
74 let mut headers = reqwest::header::HeaderMap::new();
76 headers.insert(
77 reqwest::header::AUTHORIZATION,
78 format!("Bearer {}", access_token)
79 .parse()
80 .expect("valid header value"),
81 );
82
83 let client = reqwest::Client::builder()
84 .default_headers(headers)
85 .build()?;
86
87 Ok(AuthenticatedClient {
88 client,
89 access_token,
90 email: email.to_string(),
91 })
92 }
93}