package oauth import ( "errors" "sync" "golang.org/x/oauth2" ) type TokenRefresher interface { RefreshToken(token *oauth2.Token) (*oauth2.Token, error) } type TokenSource struct { mu sync.Mutex token *oauth2.Token refresher TokenRefresher } func RefreshTokenSource(token *oauth2.Token, refresher TokenRefresher) oauth2.TokenSource { if token == nil { // allocate an (expired) token or mergeToken will fail token = new(oauth2.Token) } ts := &TokenSource{ token: token, refresher: refresher, } return ts } func (ts *TokenSource) Token() (*oauth2.Token, error) { ts.mu.Lock() defer ts.mu.Unlock() if ts.token.Valid() { return ts.token, nil } token, err := ts.refresher.RefreshToken(ts.token) if err != nil { return ts.token, err } if token.AccessToken == "" { return nil, errors.New("token refresh failed to obtain access token") } if token.RefreshToken == "" { token.RefreshToken = ts.token.RefreshToken } ts.token = token return ts.token, nil }