From b0724ddb4e8708144f04f1aabbe833ca4566af8b Mon Sep 17 00:00:00 2001 From: Umar Khan Date: Sat, 14 Feb 2026 17:57:40 -0500 Subject: [PATCH] feat: add Google Ads as an auth service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'ads' as a new service for gog auth, enabling OAuth tokens with the https://www.googleapis.com/auth/adwords scope. This allows users to obtain and refresh tokens for the Google Ads API through gog's existing auth flow. Auth-only for now — no CLI commands for the Ads API, but the token can be used with Google Ads API clients directly. --- internal/googleauth/service.go | 10 ++++++++++ internal/googleauth/service_test.go | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/internal/googleauth/service.go b/internal/googleauth/service.go index f464af91..2efc3cd3 100644 --- a/internal/googleauth/service.go +++ b/internal/googleauth/service.go @@ -25,6 +25,7 @@ const ( ServiceAppScript Service = "appscript" ServiceGroups Service = "groups" ServiceKeep Service = "keep" + ServiceAds Service = "ads" ) const ( @@ -74,6 +75,7 @@ var serviceOrder = []Service{ ServiceAppScript, ServiceGroups, ServiceKeep, + ServiceAds, } var serviceInfoByService = map[Service]serviceInfo{ @@ -203,6 +205,12 @@ var serviceInfoByService = map[Service]serviceInfo{ apis: []string{"Keep API"}, note: "Workspace only; service account (domain-wide delegation)", }, + ServiceAds: { + scopes: []string{"https://www.googleapis.com/auth/adwords"}, + user: true, + apis: []string{"Google Ads API"}, + note: "Auth only; use token with Google Ads API directly", + }, } func ParseService(s string) (Service, error) { @@ -522,6 +530,8 @@ func scopesForServiceWithOptions(service Service, opts ScopeOptions) ([]string, return Scopes(service) case ServiceKeep: return Scopes(service) + case ServiceAds: + return Scopes(service) default: return nil, errUnknownService } diff --git a/internal/googleauth/service_test.go b/internal/googleauth/service_test.go index 445de2d1..195930e5 100644 --- a/internal/googleauth/service_test.go +++ b/internal/googleauth/service_test.go @@ -65,7 +65,7 @@ func TestExtractCodeAndState_Errors(t *testing.T) { func TestAllServices(t *testing.T) { svcs := AllServices() - if len(svcs) != 15 { + if len(svcs) != 16 { t.Fatalf("unexpected: %v", svcs) } seen := make(map[Service]bool) @@ -74,7 +74,7 @@ func TestAllServices(t *testing.T) { seen[s] = true } - for _, want := range []Service{ServiceGmail, ServiceCalendar, ServiceChat, ServiceClassroom, ServiceDrive, ServiceDocs, ServiceSlides, ServiceContacts, ServiceTasks, ServicePeople, ServiceSheets, ServiceForms, ServiceAppScript, ServiceGroups, ServiceKeep} { + for _, want := range []Service{ServiceGmail, ServiceCalendar, ServiceChat, ServiceClassroom, ServiceDrive, ServiceDocs, ServiceSlides, ServiceContacts, ServiceTasks, ServicePeople, ServiceSheets, ServiceForms, ServiceAppScript, ServiceGroups, ServiceKeep, ServiceAds} { if !seen[want] { t.Fatalf("missing %q", want) } @@ -83,7 +83,7 @@ func TestAllServices(t *testing.T) { func TestUserServices(t *testing.T) { svcs := UserServices() - if len(svcs) != 13 { + if len(svcs) != 14 { t.Fatalf("unexpected: %v", svcs) } @@ -113,7 +113,7 @@ func TestUserServices(t *testing.T) { } func TestUserServiceCSV(t *testing.T) { - want := "gmail,calendar,chat,classroom,drive,docs,slides,contacts,tasks,sheets,people,forms,appscript" + want := "gmail,calendar,chat,classroom,drive,docs,slides,contacts,tasks,sheets,people,forms,appscript,ads" if got := UserServiceCSV(); got != want { t.Fatalf("unexpected user services csv: %q", got) }