func (gsa *GServiceAccount) Client(ctx context.Context, scopes ...string) (*http.Client, error) {
	b, err := gsa.TokenSource(ctx, scopes...)
	if err != nil {
		return nil, err
	}
	return b.Client(), nil
}
Client returns a HTTP client using the provided context and scopes for the
service account as the underlying transport.

When called with the appropriate scopes, the created client can be used to
create any Google API Service:

import (
dns "google.golang.org/api/dns/v2beta1"
)
cl, err := gsa.Client(ctx, dns.CloudPlatformScope, dns.NdevClouddnsReadwriteScope)
if err != nil { /* ... */ }
dnsService, err := dns.New(cl)
if err != nil { /* ... */ }

Note: this is a convenience func only.
package gserviceaccount
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"sync"
	"time"
	"github.com/kenshaw/jwt"
	"github.com/kenshaw/jwt/bearer"
	"github.com/kenshaw/pemutil"
)
const (
	DefaultAlgorithm = jwt.RS256
	DefaultExpiration = 1 * time.Hour
)
type GServiceAccount struct {
	Type                    string `json:"type,omitempty"`
	ProjectID               string `json:"project_id,omitempty"`
	PrivateKeyID            string `json:"private_key_id,omitempty"`
	PrivateKey              string `json:"private_key,omitempty"`
	ClientEmail             string `json:"client_email,omitempty"`
	ClientID                string `json:"client_id,omitempty"`
	AuthURI                 string `json:"auth_uri,omitempty"`
	TokenURI                string `json:"token_uri,omitempty"`
	AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url,omitempty"`
	ClientX509CertURL       string `json:"client_x509_cert_url,omitempty"`
	expiration time.Duration          `json:"-"`
	signer     jwt.Signer             `json:"-"`
	transport  http.RoundTripper      `json:"-"`
	claims     map[string]interface{} `json:"-"`
	mu         sync.Mutex             `json:"-"`
}
func FromJSON(buf []byte, opts ...Option) (*GServiceAccount, error) {
	gsa := &GServiceAccount{
		claims: make(map[string]interface{}),
	}
	if err := json.Unmarshal(buf, gsa); err != nil {
		return nil, err
	}
	for _, o := range opts {
		if err := o(gsa); err != nil {
			return nil, err
		}
	}
	return gsa, nil
}
func FromReader(r io.Reader, opts ...Option) (*GServiceAccount, error) {
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return FromJSON(buf, opts...)
}
func FromFile(path string, opts ...Option) (*GServiceAccount, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return FromJSON(buf, opts...)
}
func (gsa *GServiceAccount) Signer() (jwt.Signer, error) {
	gsa.mu.Lock()
	defer gsa.mu.Unlock()
	if gsa.signer == nil {
		keyset, err := pemutil.DecodeBytes([]byte(gsa.PrivateKey))
		if err != nil {
			return nil, fmt.Errorf("jwt/gserviceaccount: could not decode private key: %v", err)
		}
		keyset.AddPublicKeys()
		s, err := DefaultAlgorithm.New(keyset)
		if err != nil {
			return nil, err
		}
		gsa.signer = s
	}
	return gsa.signer, nil
}
func (gsa *GServiceAccount) TokenSource(ctx context.Context, scopes ...string) (*bearer.Bearer, error) {
	switch {
	case gsa.Type != "service_account":
		return nil, errors.New("jwt/gserviceaccount: type is not service_account")
	case gsa.ClientEmail == "":
		return nil, errors.New("jwt/gserviceaccount: missing client_email")
	case gsa.TokenURI == "":
		return nil, errors.New("jwt/gserviceaccount: missing token_uri")
	}
	signer, err := gsa.Signer()
	if err != nil {
		return nil, err
	}
	expiration := gsa.expiration
	if expiration == 0 {
		expiration = DefaultExpiration
	}
	opts := []bearer.Option{
		bearer.WithExpiresIn(expiration),
		bearer.WithIssuedAt(true),
		bearer.WithClaim("iss", gsa.ClientEmail),
		bearer.WithClaim("aud", gsa.TokenURI),
		bearer.WithScope(scopes...),
	}
	for k, v := range gsa.claims {
		opts = append(opts, bearer.WithClaim(k, v))
	}
	if gsa.transport != nil {
		opts = append(opts, bearer.WithTransport(gsa.transport))
	}
	b, err := bearer.NewTokenSource(
		signer,
		gsa.TokenURI,
		ctx,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return b, nil
}