fix: include client_secret in device code request and improve error guidance

- Include client_secret in the initial POST to /device/code endpoint
- Add check for empty GOOGLE_CLIENT_SECRET with clear error message
- Improve 'Invalid client type' error to suggest creating Desktop app OAuth client
- Include error code in addition to description for better diagnostics
This commit is contained in:
Ruben Rosario
2026-06-20 20:30:26 +01:00
parent 985e8c9bc9
commit df1c5f5c2a
+26 -5
View File
@@ -72,15 +72,25 @@ impl ApiClient {
pub async fn authenticate(&self) -> Result<(String, String), ApiError> {
if self.client_id.is_empty() {
return Err(ApiError::Auth(
"GOOGLE_CLIENT_ID not set".to_string(),
"GOOGLE_CLIENT_ID not set. Set both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET".to_string(),
));
}
if self.client_secret.is_empty() {
return Err(ApiError::Auth(
"GOOGLE_CLIENT_SECRET not set. Set both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET".to_string(),
));
}
let params = serde_json::json!({
let mut params = serde_json::json!({
"client_id": self.client_id,
"scope": "https://www.googleapis.com/auth/tasks",
});
// Some client types require client_secret in the initial request
if !self.client_secret.is_empty() {
params["client_secret"] = serde_json::Value::String(self.client_secret.clone());
}
let resp = self
.client
.post("https://oauth2.googleapis.com/device/code")
@@ -96,11 +106,22 @@ impl ApiClient {
.map_err(|e| ApiError::Api(format!("Invalid response (status {}): {}", status, e)))?;
if !status.is_success() {
let err_code = data["error"].as_str().unwrap_or("unknown_error");
let err_desc = data["error_description"]
.as_str()
.or_else(|| data["error"].as_str())
.unwrap_or("unknown error");
return Err(ApiError::Api(format!("OAuth error ({}): {}", status, err_desc)));
.unwrap_or("no description");
let mut msg = format!("OAuth error ({}): {} - {}", status, err_code, err_desc);
// Common fixes for known errors
if err_desc.contains("Invalid client") || err_code == "invalid_client" {
msg.push_str(
". Check that you created a 'Desktop app' OAuth 2.0 Client ID in Google Cloud Console \
(not 'Web application'). Also verify that Google Tasks API is enabled.",
);
}
return Err(ApiError::Api(msg));
}
let url = data["verification_url"]