Skip to content

Commit a39aaa2

Browse files
authored
fix(auth): add missing profile scope for people/me verification (#120)
* fix(auth): add missing profile scope for people/me verification gro init calls people/me with PersonFields("names,emailAddresses") to verify the People API and power `gro me`. The contacts scope covers the contacts list but not the authenticated user's own profile — Google requires userinfo.profile for that endpoint. Without this scope, gro init always fails with a 403 on the People API verification step, making fresh credential setup impossible. Closes #119 * test: update scope guardrails for userinfo.profile Update the hardcoded count in TestAllScopes (6→7) and add the scope assertion. Add userinfo.profile to the architecture test allowlist with a note that it is read-only and scoped to the authenticated user's own profile, not the contacts list.
1 parent b294bec commit a39aaa2

3 files changed

Lines changed: 9 additions & 2 deletions

File tree

internal/architecture/architecture_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ var allowedScopes = map[string]bool{
316316
"https://www.googleapis.com/auth/calendar.events": true, // RSVP, color (NOT calendar settings)
317317
"https://www.googleapis.com/auth/contacts.readonly": true,
318318
"https://www.googleapis.com/auth/contacts": true, // group membership, starring (NOT create/delete contacts)
319+
"https://www.googleapis.com/auth/userinfo.profile": true, // read authenticated user's name/email for people/me (NOT contacts list)
319320
"https://www.googleapis.com/auth/drive.readonly": true,
320321
"https://www.googleapis.com/auth/drive.metadata": true, // star/unstar files (NOT file content write)
321322
}

internal/auth/auth.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ import (
2626
// The architecture test (TestNoDestructiveAPIMethodsInProductionCode) prevents accidental misuse.
2727
// Contacts uses the full contacts scope for group management and starring.
2828
// The contacts scope is a superset of contacts.readonly — it includes all read access.
29+
// Profile is required for people/me (names, emailAddresses fields) used by `gro me` and init verification.
2930
var AllScopes = []string{
3031
gmail.GmailModifyScope,
3132
calendar.CalendarReadonlyScope,
3233
calendar.CalendarEventsScope,
3334
people.ContactsScope,
35+
people.UserinfoProfileScope,
3436
drive.DriveReadonlyScope,
3537
drive.DriveMetadataScope,
3638
}
@@ -43,6 +45,7 @@ var ScopeDescriptions = map[string]string{
4345
calendar.CalendarEventsScope: "Calendar Events — read and update events (RSVP, color). No calendar settings access.",
4446
people.ContactsScope: "Contacts — read contacts and groups, plus manage group membership and starring.",
4547
people.ContactsReadonlyScope: "Contacts Read-Only — read contacts and groups.",
48+
people.UserinfoProfileScope: "Profile — read the authenticated user's name and email address (required for 'gro me').",
4649
drive.DriveReadonlyScope: "Drive Read-Only — read files and metadata.",
4750
drive.DriveMetadataScope: "Drive Metadata — read and update file metadata (star/unstar). No file content write access.",
4851
}

internal/auth/auth_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ func TestDeprecatedWrappers(t *testing.T) {
101101

102102
func TestAllScopes(t *testing.T) {
103103
t.Parallel()
104-
if len(AllScopes) != 6 {
105-
t.Errorf("got length %d, want %d", len(AllScopes), 6)
104+
if len(AllScopes) != 7 {
105+
t.Errorf("got length %d, want %d", len(AllScopes), 7)
106106
}
107107
scopeSet := strings.Join(AllScopes, " ")
108108
if !strings.Contains(scopeSet, "https://www.googleapis.com/auth/gmail.modify") {
@@ -123,6 +123,9 @@ func TestAllScopes(t *testing.T) {
123123
if !strings.Contains(scopeSet, "https://www.googleapis.com/auth/drive.metadata") {
124124
t.Errorf("expected AllScopes to contain %q", "https://www.googleapis.com/auth/drive.metadata")
125125
}
126+
if !strings.Contains(scopeSet, "https://www.googleapis.com/auth/userinfo.profile") {
127+
t.Errorf("expected AllScopes to contain %q", "https://www.googleapis.com/auth/userinfo.profile")
128+
}
126129
}
127130

128131
func TestCheckScopesMigration_NoGrantedScopes(t *testing.T) {

0 commit comments

Comments
 (0)