Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .changeset/remove-dwd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@googleworkspace/cli": minor
---

Remove domain wide delegation support
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ Use these labels to categorize pull requests and issues:
| `GOOGLE_WORKSPACE_CLI_TOKEN` | Pre-obtained OAuth2 access token (highest priority; bypasses all credential file loading) |
| `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` | Path to OAuth credentials JSON (no default; if unset, falls back to credentials secured by the OS Keyring and encrypted in `~/.config/gws/`) |
| `GOOGLE_WORKSPACE_CLI_ACCOUNT` | Default account email for multi-account usage (overridden by `--account` flag) |
| `GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER` | Email of user to impersonate with Domain-Wide Delegation (service accounts only) |
| `GOOGLE_APPLICATION_CREDENTIALS` | Standard Google ADC path; used as fallback when no gws-specific credentials are configured |

### Configuration
Expand Down
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,6 @@ export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/service-account.json
gws drive files list
```

For Domain-Wide Delegation, add:

```bash
export GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=admin@example.com
```

### Pre-obtained Access Token

Useful when another tool (e.g. `gcloud`) already mints tokens for your environment.
Expand Down Expand Up @@ -366,7 +360,6 @@ All variables are optional. See [`.env.example`](.env.example) for a copy-paste
| `GOOGLE_WORKSPACE_CLI_TOKEN` | Pre-obtained OAuth2 access token (highest priority) |
| `GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE` | Path to OAuth credentials JSON (user or service account) |
| `GOOGLE_WORKSPACE_CLI_ACCOUNT` | Default account email (overridden by `--account` flag) |
| `GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER` | Email for Domain-Wide Delegation (service accounts) |
| `GOOGLE_WORKSPACE_CLI_CLIENT_ID` | OAuth client ID (alternative to `client_secret.json`) |
| `GOOGLE_WORKSPACE_CLI_CLIENT_SECRET` | OAuth client secret (paired with `CLIENT_ID`) |
| `GOOGLE_WORKSPACE_CLI_CONFIG_DIR` | Override config directory (default: `~/.config/gws`) |
Expand Down
21 changes: 3 additions & 18 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ pub async fn get_token(scopes: &[&str], account: Option<&str>) -> anyhow::Result
}

let creds_file = std::env::var("GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE").ok();
let impersonated_user = std::env::var("GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER").ok();
let config_dir = crate::auth_commands::config_dir();

// If env var credentials are specified, skip account resolution entirely
Expand All @@ -90,7 +89,7 @@ pub async fn get_token(scopes: &[&str], account: Option<&str>) -> anyhow::Result
let default_path = config_dir.join("credentials.json");
let token_cache = config_dir.join("token_cache.json");
let creds = load_credentials_inner(creds_file.as_deref(), &enc_path, &default_path).await?;
return get_token_inner(scopes, creds, &token_cache, impersonated_user.as_deref()).await;
return get_token_inner(scopes, creds, &token_cache).await;
}

// Resolve account from registry
Expand All @@ -113,13 +112,7 @@ pub async fn get_token(scopes: &[&str], account: Option<&str>) -> anyhow::Result

let default_path = config_dir.join("credentials.json");
let creds = load_credentials_inner(None, &enc_path, &default_path).await?;
get_token_inner(
scopes,
creds,
&token_cache_path,
impersonated_user.as_deref(),
)
.await
get_token_inner(scopes, creds, &token_cache_path).await
}

/// Resolve which account to use:
Expand Down Expand Up @@ -174,7 +167,6 @@ async fn get_token_inner(
scopes: &[&str],
creds: Credential,
token_cache_path: &std::path::Path,
impersonated_user: Option<&str>,
) -> anyhow::Result<String> {
match creds {
Credential::AuthorizedUser(secret) => {
Expand All @@ -198,17 +190,10 @@ async fn get_token_inner(
.map(|f| f.to_string_lossy().to_string())
.unwrap_or_else(|| "token_cache.json".to_string());
let sa_cache = token_cache_path.with_file_name(format!("sa_{tc_filename}"));
let mut builder = yup_oauth2::ServiceAccountAuthenticator::builder(key).with_storage(
let builder = yup_oauth2::ServiceAccountAuthenticator::builder(key).with_storage(
Box::new(crate::token_storage::EncryptedTokenStorage::new(sa_cache)),
);

// Check for impersonation
if let Some(user) = impersonated_user {
if !user.trim().is_empty() {
builder = builder.subject(user.to_string());
}
}

let auth = builder
.build()
.await
Expand Down
2 changes: 1 addition & 1 deletion src/auth_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1507,7 +1507,7 @@ const SCOPE_ENTRIES: &[ScopeEntry] = &[
// (parse_scopes removed — replaced by resolve_scopes above)

/// Helper: check if a scope can't be used with user OAuth consent flow
/// (requires a Chat app, service account, or domain-wide delegation).
/// (requires a Chat app or service account).
fn is_app_only_scope(url: &str) -> bool {
url.contains("/auth/chat.app.")
|| url.contains("/auth/chat.bot")
Expand Down
3 changes: 0 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,6 @@ fn print_usage() {
println!(
" GOOGLE_WORKSPACE_CLI_ACCOUNT Default account email for multi-account"
);
println!(
" GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER Email for Domain-Wide Delegation (service accounts)"
);
println!(
" GOOGLE_WORKSPACE_CLI_CONFIG_DIR Override config directory (default: ~/.config/gws)"
);
Expand Down
2 changes: 1 addition & 1 deletion src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ pub async fn fetch_scopes_for_apis(enabled_api_ids: &[String]) -> Vec<Discovered
continue;
}
// Filter out scopes that can't be used with user OAuth consent
// (they require a Chat app, service account, or domain-wide delegation)
// (they require a Chat app or service account)
if url.contains("/auth/chat.app.")
|| url.contains("/auth/chat.bot")
|| url.contains("/auth/chat.import")
Expand Down
Loading