I've seen lots of documentation on Google API clients for users, but very little on using a service account. This isn't on behalf of a user, I'm just trying to get a client working with the Calendar APIs using a client ID and client secret, which would be provided via environment variables for me (I'd prefer to not read from a file).
Here's what I have so far:
package main
import (
"context"
clientCredentials "golang.org/x/oauth2/clientcredentials"
google "golang.org/x/oauth2/google"
calendar "google.golang.org/api/calendar/v3"
apiOption "google.golang.org/api/option"
)
func main() {
config := &clientCredentials.Config{
ClientID: "<my_id>",
ClientSecret: "-----BEGIN PRIVATE KEY-----\n...",
TokenURL: google.Endpoint.TokenURL,
}
ctx := context.Background()
client := config.Client(ctx)
service, _ := calendar.NewService(ctx, apiOption.WithHTTPClient(client))
calendarList, err := service.CalendarList.List().Do()
}
But I'm getting the following error:
Get "https://www.googleapis.com/calendar/v3/users/me/calendarList?alt=json&prettyPrint=false": oauth2: cannot fetch token: 400 Bad Request
Response: {
"error": "unsupported_grant_type",
"error_description": "Invalid grant_type: client_credentials"
}
Any help here is greatly appreciated! I'm new to Golang, Oauth2, and Google APIs :)
The answer from @Tanaike got me on the right track. This is what I ended up using:
package main
import (
"context"
"encoding/json"
"fmt"
googleOauth "golang.org/x/oauth2/google"
calendar "google.golang.org/api/calendar/v3"
apiOption "google.golang.org/api/option"
)
var service *calendar.Service
// Note that some of the fields are optional:
type GoogleAuthConfig struct {
Type string `json:"type"`
ProjectID string `json:"project_id,omitempty"`
ClientEmail string `json:"client_email"`
ClientID string `json:"client_id,omitempty"`
ClientSecret string `json:"private_key"`
ClientSecretID string `json:"private_key_id,omitempty"`
AuthURL string `json:"auth_uri,omitempty"`
TokenURL string `json:"token_uri,omitempty"`
AuthProviderCertURL string `json:"auth_provider_x509_cert_url,omitempty"`
ClientCertURL string `json:"client_x509_cert_url,omitempty"`
}
func main() {
authConfig := GoogleAuthConfig{
Type: "service_account",
ClientEmail: "account123@project-456.iam.gserviceaccount.com",
ClientID: "1234",
ClientSecret: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
AuthURL: googleOauth.Endpoint.AuthURL,
TokenURL: googleOauth.Endpoint.TokenURL,
}
authConfigJson, err := json.Marshal(authConfig)
ctx := context.Background()
service, err = calendar.NewService(ctx, apiOption.WithCredentialsJSON([]byte(authConfigJson)))
}
Note that I didn't have to configure domain-wide delegation or impersonate a user; this worked fine after I added the service account to the calendar.
Service accounts still need to accept calendar invites after you add the account email to the calendar. This can be done with the following:
entry := calendar.CalendarListEntry{Id: calendarID}
service.CalendarList.Insert(&entry).Do()