func SetAccessToken() error {
	if GetApigeeToken() == "" && GetServiceAccount() == "" {
		SetApigeeToken(GetToken())  
		if GetApigeeToken() == "" {
			return fmt.Errorf("either token or service account must be provided")
		}
		if checkAccessToken() {  
			return nil
		}
		return fmt.Errorf("token expired: request a new access token or pass the service account")
	}
	if GetApigeeToken() != "" {
		if checkAccessToken() {
			_ = WriteToken(GetApigeeToken())
			return nil
		}
	} else {
		err := readServiceAccount(GetServiceAccount())
		if err != nil {  
			return fmt.Errorf("error reading config file: %s", err)
		}
		privateKey := getServiceAccountProperty("PrivateKey")
		if privateKey == "" {
			return fmt.Errorf("private key missing in the service account")
		}
		if getServiceAccountProperty("ClientEmail") == "" {
			return fmt.Errorf("client email missing in the service account")
		}
		_, err = generateAccessToken(privateKey)
		if err != nil {
			return fmt.Errorf("fatal error generating access token: %s", err)
		}
		return nil
	}
	return fmt.Errorf("token expired: request a new access token or pass the service account")
}
SetAccessToken read from cache or if not found or expired will generate a new one
package apiclient
import (
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
	"github.com/lestrrat/go-jwx/jwa"
	"github.com/lestrrat/go-jwx/jwt"
	"github.com/srinandan/apigeecli/clilog"
)
type serviceAccount 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"`
	AuthProviderCertURL string `json:"auth_provider_x509_cert_url,omitempty"`
	ClientCertURL       string `json:"client_x509_cert_url,omitempty"`
}
var account = serviceAccount{}
func getPrivateKey(privateKey string) (interface{}, error) {
	pemPrivateKey := fmt.Sprintf("%v", privateKey)
	block, _ := pem.Decode([]byte(pemPrivateKey))
	privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		clilog.Error.Println("error parsing Private Key: ", err)
		return nil, err
	}
	return privKey, nil
}
func generateJWT(privateKey string) (string, error) {
	const aud = "https://www.googleapis.com/oauth2/v4/token"
	const scope = "https://www.googleapis.com/auth/cloud-platform"
	privKey, err := getPrivateKey(privateKey)
	if err != nil {
		return "", err
	}
	now := time.Now()
	token := jwt.New()
	_ = token.Set(jwt.AudienceKey, aud)
	_ = token.Set(jwt.IssuerKey, getServiceAccountProperty("ClientEmail"))
	_ = token.Set("scope", scope)
	_ = token.Set(jwt.IssuedAtKey, now.Unix())
	_ = token.Set(jwt.ExpirationKey, now.Unix())
	payload, err := token.Sign(jwa.RS256, privKey)
	if err != nil {
		clilog.Error.Println("error parsing Private Key: ", err)
		return "", err
	}
	clilog.Info.Println("jwt token : ", string(payload))
	return string(payload), nil
}
func generateAccessToken(privateKey string) (string, error) {
	const tokenEndpoint = "https://oauth2.googleapis.com/token"
	const grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
	var respBody []byte
	type oAuthAccessToken struct {
		AccessToken string `json:"access_token,omitempty"`
		ExpiresIn   int    `json:"expires_in,omitempty"`
		TokenType   string `json:"token_type,omitempty"`
	}
	token, err := generateJWT(privateKey)
	if err != nil {
		return "", nil
	}
	form := url.Values{}
	form.Add("grant_type", grantType)
	form.Add("assertion", token)
	client := &http.Client{}
	req, err := http.NewRequest("POST", tokenEndpoint, strings.NewReader(form.Encode()))
	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return "", err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
	resp, err := client.Do(req)
	if err != nil {
		clilog.Error.Println("failed to generate oauth token: ", err)
		return "", err
	}
	if resp != nil {
		defer resp.Body.Close()
	}
	if resp == nil {
		clilog.Error.Println("error in response: Response was null")
		return "", errors.New("error in response: Response was null")
	}
	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("error in response: ", err)
		return "", fmt.Errorf("error in response: ", err)
	} else if resp.StatusCode > 399 {
		clilog.Error.Printf("status code %d, error in response: %s\n", resp.StatusCode, string(respBody))
		return "", fmt.Errorf("status code %d, error in response: %s\n", resp.StatusCode, string(respBody))
	}
	accessToken := oAuthAccessToken{}
	if err = json.Unmarshal(respBody, &accessToken); err != nil {
		return "", err
	}
	clilog.Info.Println("access token : ", accessToken)
	SetApigeeToken(accessToken.AccessToken)
	_ = WriteToken(accessToken.AccessToken)
	return accessToken.AccessToken, nil
}
func readServiceAccount(serviceAccountPath string) error {
	content, err := ioutil.ReadFile(serviceAccountPath)
	if err != nil {
		return err
	}
	err = json.Unmarshal(content, &account)
	if err != nil {
		return err
	}
	return nil
}
func getServiceAccountProperty(key string) (value string) {
	r := reflect.ValueOf(&account)
	field := reflect.Indirect(r).FieldByName(key)
	return field.String()
}
func checkAccessToken() bool {
	if IsSkipCheck() {
		clilog.Info.Println("skipping token validity")
		return true
	}
	const tokenInfo = "https://oauth2.googleapis.com/tokeninfo"
	u, _ := url.Parse(tokenInfo)
	q := u.Query()
	q.Set("access_token", GetApigeeToken())
	u.RawQuery = q.Encode()
	client := &http.Client{}
	clilog.Info.Println("Connecting to : ", u.String())
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		clilog.Error.Println("error in client:", err)
		return false
	}
	resp, err := client.Do(req)
	if err != nil {
		clilog.Error.Println("error connecting to token endpoint: ", err)
		return false
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("token info error: ", err)
		return false
	} else if resp.StatusCode != 200 {
		clilog.Error.Println("token expired: ", string(body))
		return false
	}
	clilog.Info.Println("Response: ", string(body))
	clilog.Info.Println("Reusing the cached token: ", GetApigeeToken())
	return true
}