package googleapi import ( "encoding/json" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/timeext" "io" "net/http" "sync" "time" ) type GoogleOAuth interface { } type oauth struct { clientID string clientSecret string refreshToken string lock sync.RWMutex accessToken *string expiryDate *time.Time } func NewGoogleOAuth(clientid string, clientsecret, refreshtoken string) GoogleOAuth { return &oauth{ clientID: clientid, clientSecret: clientsecret, refreshToken: refreshtoken, } } func (c *oauth) AccessToken() (string, error) { c.lock.RLock() if c.accessToken != nil && c.expiryDate != nil && (*c.expiryDate).After(time.Now()) { c.lock.RUnlock() return *c.accessToken, nil // still valid } c.lock.RUnlock() httpclient := http.Client{} req, err := http.NewRequest(http.MethodPost, "https://oauth2.googleapis.com/token", nil) if err != nil { return "", err } req.URL.Query().Add("client_id", c.clientID) req.URL.Query().Add("client_secret", c.clientSecret) req.URL.Query().Add("grant_type", "refresh_token") req.URL.Query().Add("refresh_token", c.refreshToken) reqStartTime := time.Now() res, err := httpclient.Do(req) type response struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` Scope string `json:"scope"` TokenType string `json:"token_type"` } var r response data, err := io.ReadAll(res.Body) if err != nil { return "", err } err = json.Unmarshal(data, &r) if err != nil { return "", err } c.lock.Lock() c.expiryDate = langext.Ptr(reqStartTime.Add(timeext.FromSeconds(r.ExpiresIn - 10))) c.accessToken = langext.Ptr(r.AccessToken) c.lock.Unlock() return r.AccessToken, nil }