Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changeset/fix-auth-status-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
---\n"gws": patch\n---\n\nfix(auth): report token info in status when using GOOGLE_WORKSPACE_CLI_TOKEN to improve clarity
160 changes: 82 additions & 78 deletions src/auth_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,91 +1067,95 @@ async fn handle_status() -> Result<(), GwsError> {
}
} // end !cfg!(test)

// If we have credentials, try to get live info (user, scopes, APIs)
// If we have credentials or a direct token, try to get live info (user, scopes, APIs)
// Skip all network calls and subprocess spawning in test builds
if !cfg!(test) {
let creds_json_str = if has_encrypted {
credential_store::load_encrypted().ok()
} else if has_plain {
tokio::fs::read_to_string(&plain_path).await.ok()
let direct_token = std::env::var("GOOGLE_WORKSPACE_CLI_TOKEN")
.ok()
.filter(|t| !t.is_empty());

let access_token = if let Some(token) = direct_token {
Some(token)
} else {
None
};
let creds_json_str = if has_encrypted {
credential_store::load_encrypted().ok()
} else if has_plain {
tokio::fs::read_to_string(&plain_path).await.ok()
} else {
None
};

if let Some(creds_str) = creds_json_str {
if let Ok(creds) = serde_json::from_str::<serde_json::Value>(&creds_str) {
let client_id = creds.get("client_id").and_then(|v| v.as_str());
let client_secret = creds.get("client_secret").and_then(|v| v.as_str());
let refresh_token = creds.get("refresh_token").and_then(|v| v.as_str());

if let (Some(cid), Some(csec), Some(rt)) = (client_id, client_secret, refresh_token)
{
// Exchange refresh token for access token
let http_client = reqwest::Client::new();
let token_resp = http_client
.post("https://oauth2.googleapis.com/token")
.form(&[
("client_id", cid),
("client_secret", csec),
("refresh_token", rt),
("grant_type", "refresh_token"),
])
.send()
.await;

if let Ok(resp) = token_resp {
if let Ok(token_json) = resp.json::<serde_json::Value>().await {
if let Some(access_token) =
token_json.get("access_token").and_then(|v| v.as_str())
{
output["token_valid"] = json!(true);

// Get user info
if let Ok(user_resp) = http_client
.get("https://www.googleapis.com/oauth2/v1/userinfo")
.bearer_auth(access_token)
.send()
.await
{
if let Ok(user_json) =
user_resp.json::<serde_json::Value>().await
{
if let Some(email) =
user_json.get("email").and_then(|v| v.as_str())
{
output["user"] = json!(email);
}
}
}

// Get granted scopes via tokeninfo
let tokeninfo_url = format!(
"https://oauth2.googleapis.com/tokeninfo?access_token={}",
access_token
);
if let Ok(info_resp) = http_client.get(&tokeninfo_url).send().await
{
if let Ok(info_json) =
info_resp.json::<serde_json::Value>().await
{
if let Some(scope_str) =
info_json.get("scope").and_then(|v| v.as_str())
{
let scopes: Vec<&str> = scope_str.split(' ').collect();
output["scopes"] = json!(scopes);
output["scope_count"] = json!(scopes.len());
}
}
}
if let Some(creds_str) = creds_json_str {
if let Ok(creds) = serde_json::from_str::<serde_json::Value>(&creds_str) {
let client_id = creds.get("client_id").and_then(|v| v.as_str());
let client_secret = creds.get("client_secret").and_then(|v| v.as_str());
let refresh_token = creds.get("refresh_token").and_then(|v| v.as_str());

if let (Some(cid), Some(csec), Some(rt)) =
(client_id, client_secret, refresh_token)
{
// Exchange refresh token for access token
let http_client = reqwest::Client::new();
let token_resp = http_client
.post("https://oauth2.googleapis.com/token")
.form(&[
("client_id", cid),
("client_secret", csec),
("refresh_token", rt),
("grant_type", "refresh_token"),
])
.send()
.await;

if let Ok(resp) = token_resp {
if let Ok(token_json) = resp.json::<serde_json::Value>().await {
token_json
.get("access_token")
.and_then(|v| v.as_str())
.map(|s| s.to_string())
} else {
output["token_valid"] = json!(false);
if let Some(err) =
token_json.get("error_description").and_then(|v| v.as_str())
{
output["token_error"] = json!(err);
}
None
}
} else {
None
}
} else {
None
}
} else {
None
}
} else {
None
}
};

if let Some(at) = access_token {
output["token_valid"] = json!(true);
let http_client = reqwest::Client::new();

// Get user info
if let Ok(user_resp) = http_client
.get("https://www.googleapis.com/oauth2/v1/userinfo")
.bearer_auth(&at)
.send()
.await
{
if let Ok(user_json) = user_resp.json::<serde_json::Value>().await {
if let Some(email) = user_json.get("email").and_then(|v| v.as_str()) {
output["user"] = json!(email);
}
}
}

// Get granted scopes via tokeninfo
let tokeninfo_url = format!("https://oauth2.googleapis.com/tokeninfo?access_token={}", at);
if let Ok(info_resp) = http_client.get(&tokeninfo_url).send().await {
if let Ok(info_json) = info_resp.json::<serde_json::Value>().await {
if let Some(scope_str) = info_json.get("scope").and_then(|v| v.as_str()) {
let scopes: Vec<&str> = scope_str.split(' ').collect();
output["scopes"] = json!(scopes);
output["scope_count"] = json!(scopes.len());
}
}
}
Expand Down
Loading