'Google Apps API 403 with Service Account

I've been trying make a query against Google's Admin API to list all users in my Google Apps Organization. I have permissions to make this query in the web UI example and get results, but it 403's when I try to make the query with a service account.

import (
    "fmt"
    "io/ioutil"
    "log"

    "golang.org/x/net/context"
    "golang.org/x/oauth2/google"
    directory "google.golang.org/api/admin/directory_v1"
)

func main() {
    serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFile)
    if err != nil {
        log.Fatalf("Could not read service account credentials file, %s => {%s}", serviceAccountFile, err)
    }
    config, err := google.JWTConfigFromJSON(serviceAccountJSON,
        directory.AdminDirectoryUserScope,
        directory.AdminDirectoryUserReadonlyScope,
    )

    client, err := directory.New(config.Client(context.Background()))
    if err != nil {
        log.Fatalf("Could not create directory service client => {%s}", err)
    }

    users, err := client.Users.List().ViewType(publicDataView).Domain(domain).Do()
    if err != nil {
        log.Fatalf("Failed to query all users => {%s}", err)
    }

    for _, u := range users.Users {
        fmt.Println(u.Name.FullName)
    }
}

Every time I execute I get a 403. The same query parameters works in the Try it! section here so I'm not sure why it fails.

result: Failed to query all users => {googleapi: Error 403: Not Authorized to access this resource/api, forbidden}



Solution 1:[1]

I know this question is a year old, but I couldnt find anything about this anywhere - but ive just managed to fix it after running into the same error as you.

basically you need to set a delegation user to your config, eg:

func main() {
    serviceAccountJSON, err := ioutil.ReadFile(serviceAccountFile)
    if err != nil {
        log.Fatalf("Could not read service account credentials file, %s => {%s}", serviceAccountFile, err)
    }
    config, err := google.JWTConfigFromJSON(serviceAccountJSON,
        directory.AdminDirectoryUserScope,
        directory.AdminDirectoryUserReadonlyScope,
    )

    // Add me
    config.Subject = "[email protected]"

    client, err := directory.New(config.Client(context.Background()))
    if err != nil {
        log.Fatalf("Could not create directory service client => {%s}", err)
    }

    users, err := client.Users.List().ViewType(publicDataView).Domain(domain).Do()
    if err != nil {
        log.Fatalf("Failed to query all users => {%s}", err)
    }

    for _, u := range users.Users {
        fmt.Println(u.Name.FullName)
    }
}

See https://github.com/golang/oauth2/blob/master/google/example_test.go#L118

hope this helps someone else!

Solution 2:[2]

The @Chronojam reply saved me hours, however on the newer versions of the Google SDK directory.New is deprecated, you should be achieve the same thing replacing the directory.New(...) line with this one instead:

    client, err := directory.NewService(context.Background(), option.WithHTTPClient(config.Client(context.Background())))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chronojam
Solution 2 kuteninja