【GO】GoogleOAuthの管理パッケージがいい感じにできた

## ソースの流れとOAuthについて
最後に全文載せてるので使ってください。
たぶんほぼそのまま動くと思います。

OAuth 2.0 は、ユーザーが安全に認証情報を提供せずに、サードパーティアプリケーションにアクセスを許可するための標準的な認可プロトコルです。

このパッケージは Google OAuth を利用し、アクセストークンの取得やリフレッシュ、ユーザー情報の取得を管理する機能を提供します。基本的な流れは以下の通り。

1. `NewGoogleOAuthManager` で Google OAuth 設定を生成。
2. `GetAccessToken` で認可コードを使用してアクセストークンを取得。
3. `RefreshAccessToken` でリフレッシュトークンを用いて新しいアクセストークンを取得。
4. `createOAuthInfo` でアクセストークンを元にユーザー情報を取得。

## メソッドの説明

### `NewGoogleOAuthManager(redirectURL string) *GoogleOAuthManager`
環境変数から `ClientID` と `ClientSecret` を取得し、Google OAuth 設定を生成する。

### `GetAccessToken(code string) (*OAuthInfo, error)`
Google OAuth 認可コードを使用し、アクセストークンを取得。ユーザー情報を `OAuthInfo` 構造体に格納して返す。

### `RefreshAccessToken(refreshToken string) (*OAuthInfo, error)`
リフレッシュトークンを利用し、新しいアクセストークンを取得する。

### `createOAuthInfo(ctx context.Context, tokenInfo *oauth2.Token) (*OAuthInfo, error)`
アクセストークンを元に Google のユーザー情報を取得し、`OAuthInfo` 構造体に格納する。

## インポートの書き方に注意
Google OAuth ライブラリを使用しています。
https://pkg.go.dev/golang.org/x/oauth2/google

```go
import (
	"golang.org/x/oauth2"
	googleOAuth "golang.org/x/oauth2/google"
	v2 "google.golang.org/api/oauth2/v2"
)

```
### 必要なライブラリのインストール
以下のコマンドを実行して、必要なライブラリを取得してください。

```bash
go get golang.org/x/oauth2
go get golang.org/x/oauth2/google
```

### 注意点
- `googleOAuth` というエイリアスを付けて `google.Endpoint` を使用する。
- `v2 "google.golang.org/api/oauth2/v2"` を用いて Google API の `Tokeninfo` を取得する。

## ソースコード全文

```go
package infra

import (
	"context"
	"develop-app/utils"
	"errors"
	"os"

	"golang.org/x/oauth2"
	googleOAuth "golang.org/x/oauth2/google"
	v2 "google.golang.org/api/oauth2/v2"
)

type IGoogleOAuthManager interface {
	GetAccessToken(code string) (oAuthInfo *OAuthInfo, err error)
}

type GoogleOAuthManager struct {
	Config *oauth2.Config
}

func NewGoogleOAuthManager(redirectURL string) *GoogleOAuthManager {
	return newGoogleOAuthManager(
		os.Getenv("GOOGLE_CLIENT_ID"),
		os.Getenv("GOOGLE_CLIENT_SECRET"),
		redirectURL,
	)
}

func newGoogleOAuthManager(clientId string, clientSecret string, redirectURL string) *GoogleOAuthManager {
	googleOAuthManager := &GoogleOAuthManager{
		Config: &oauth2.Config{
			ClientID:     clientId,
			ClientSecret: clientSecret,
			Endpoint:     googleOAuth.Endpoint,
			Scopes:       []string{"openid", "email"},
			RedirectURL:  redirectURL,
		},
	}

	if googleOAuthManager.Config == nil {
		panic("==== invalid key. google api ====")
	}

	return googleOAuthManager
}

func (g *GoogleOAuthManager) GetAccessToken(code string) (oAuthInfo *OAuthInfo, err error) {
	utils.CustomLogger(utils.Debug, "GetAccessToken")
	cxt := context.Background()
	tokenInfo, _ := g.Config.Exchange(cxt, code)
	if tokenInfo == nil {
		utils.CustomLogger(utils.Error, utils.FailedGetGoogleToken)
		return nil, errors.New(utils.FailedGetGoogleToken)
	}
	googleAccessToken := tokenInfo.AccessToken

	client := g.Config.Client(cxt, tokenInfo)
	service, err := v2.New(client)
	if err != nil {
		utils.CustomLogger(utils.Error, utils.GoogleTokenClientError+":"+err.Error())
		return nil, err
	}

	userInfo, err := service.Tokeninfo().AccessToken(googleAccessToken).Context(cxt).Do()
	if err != nil {
		utils.CustomLogger(utils.Error, err.Error())
		return nil, err
	}

	oAuthInfo = &OAuthInfo{
		Email:        userInfo.Email,
		AccessToken:  googleAccessToken,
		RefreshToken: tokenInfo.RefreshToken,
		Expiry:       tokenInfo.Expiry.Unix(),
	}

	return oAuthInfo, nil
}

func (g *GoogleOAuthManager) RefreshAccessToken(refreshToken string) (*OAuthInfo, error) {
	if refreshToken == "" {
		return nil, errors.New(utils.RefreshTokenIsRequired)
	}
	cxt := context.Background()
	tokenSource := g.Config.TokenSource(cxt, &oauth2.Token{RefreshToken: refreshToken})
	newToken, err := tokenSource.Token()
	if err != nil {
		return nil, errors.New(utils.FailedToRefreshAccessToken + ":" + err.Error())
	}

	return g.createOAuthInfo(cxt, newToken)
}

func (g *GoogleOAuthManager) createOAuthInfo(cxt context.Context, tokenInfo *oauth2.Token) (*OAuthInfo, error) {
	client := g.Config.Client(cxt, tokenInfo)
	service, err := v2.New(client)
	if err != nil {
		utils.CustomLogger(utils.Error, utils.FailedToCreateOAuth2Service+":"+err.Error())
		return nil, errors.New(utils.FailedToCreateOAuth2Service)
	}

	userInfo, err := service.Tokeninfo().AccessToken(tokenInfo.AccessToken).Context(cxt).Do()
	if err != nil {
		utils.CustomLogger(utils.Error, utils.FailedToFetchGoogleUserInfo+":"+err.Error())
		return nil, errors.New(utils.FailedToFetchGoogleUserInfo)
	}

	return &OAuthInfo{
		Email:        userInfo.Email,
		AccessToken:  tokenInfo.AccessToken,
		RefreshToken: tokenInfo.RefreshToken,
		Expiry:       tokenInfo.Expiry.Unix(),
	}, nil
}

type OAuthInfo struct {
	Email        string
	AccessToken  string
	Expiry       int64
	RefreshToken string
}
```