I want to query GSuite Admin SDK Directory API to return all users in a group, in Go, and authenticated as a GCP service account (the script will be executed in a Google Compute Engine VM or as a Google Cloud Function).
The service account I use (let's call it [email protected]
) have been granted necessary scopes in GSuite :
- https://www.googleapis.com/auth/admin.directory.group.member.readonly
- https://www.googleapis.com/auth/admin.directory.group.member
- https://www.googleapis.com/auth/admin.directory.group.readonly
- https://www.googleapis.com/auth/admin.directory.group
At my disposal, I also have a GSuite Admin account (let's call it [email protected]
). This account will be used for delegation (see the docs on delegation).
I am able to return all users in a group with the following code (based on the code in the link provided above, and I have removed most of error handling to make the code shorter) :
package main
import (
"io/ioutil"
"log"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
)
func main() {
srv := createAdminDirectoryService(
os.Getenv("SERVICE_ACCOUNT_FILE_PATH"),
os.Getenv("GSUITE_ADMIN_USER_EMAIL"),
)
members := listUsersInGroup(srv, os.Args[1])
log.Println(members)
}
func createAdminDirectoryService(serviceAccountFilePath,
gsuiteAdminUserEmail string) *admin.Service {
jsonCredentials, _ := ioutil.ReadFile(serviceAccountFilePath)
config, _ := google.JWTConfigFromJSON(
jsonCredentials,
admin.AdminDirectoryGroupMemberReadonlyScope,
)
config.Subject = gsuiteAdminUserEmail
ctx := context.Background()
client := config.Client(ctx)
srv, _ := admin.New(client)
return srv
}
func listUsersInGroup(srv *admin.Service, groupEmail string) []string {
members, err := srv.Members.List(groupEmail).Do()
if err != nil {
log.Fatal(err)
}
membersEmails := make([]string, len(members.Members))
for i, member := range members.Members {
membersEmails[i] = member.Email
}
return membersEmails
}
As you can see, that code requires to have a JSON key file of [email protected]
. This is the only way I have found to create a jwt.Config
object.
Moreover, note that delegation is done with the line config.Subject = gsuiteAdminUserEmail
; without that, I got the error :
googleapi: Error 403: Insufficient Permission: Request had insufficient authentication scopes., insufficientPermissions
Anyway, running :
SERVICE_ACCOUNT_FILE_PATH=/path/to/json/key/of/my/service/account \
[email protected] \
go run main.go [email protected]
prints with success all users in [email protected]
.
However, since this code will be run from a Google Compute Engine VM (or a Google Cloud Function) with [email protected]
used as service account, it seems ridiculous to need a JSON key of that service account to authenticate (since I am already authenticated as [email protected]
, on the VM or inside the GCF).
I have tried to replace the content of createAdminDirectoryService()
with the following code to authenticate as the user who launched the script (with default credentials) :
func createAdminDirectoryService() *admin.Service {
ctx := context.Background()
client, _ := google.DefaultClient(ctx, scopes...)
srv, _ := admin.New(client)
return srv
}
But listing users returns an error :
googleapi: Error 403: Insufficient Permission: Request had insufficient authentication scopes., insufficientPermissions
As this is the same error I have got when I removed the delegation, I think this is related. Indeed, I did not provide my GSuite Admin account anywhere during the admin.Service
creation.
Can anyone help about one of these points :
- How can I authenticate directly with the user running the go script on a Google Compute Engine VM, or a Google Cloud Function?
- Do I really need a JSON key file to generate a
jwt.Config
object? - I have looked into the source code of
golang.org/x/oauth2/google
, I could get aoauth2.Config
instead ofjwt.Config
, but it does not seem possible to "delegate" with a oauth2 token. How else can I perform the delegation?