ソースの流れとOAuthについて
最後に全文載せてるので使ってください。
たぶんほぼそのまま動くと思います。
OAuth 2.0 は、ユーザーが安全に認証情報を提供せずに、サードパーティアプリケーションにアクセスを許可するための標準的な認可プロトコルです。
このパッケージは Google OAuth を利用し、アクセストークンの取得やリフレッシュ、ユーザー情報の取得を管理する機能を提供します。基本的な流れは以下の通り。
-
NewGoogleOAuthManager
で Google OAuth 設定を生成。 -
GetAccessToken
で認可コードを使用してアクセストークンを取得。 -
RefreshAccessToken
でリフレッシュトークンを用いて新しいアクセストークンを取得。 -
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
import (
"golang.org/x/oauth2"
googleOAuth "golang.org/x/oauth2/google"
v2 "google.golang.org/api/oauth2/v2"
)
必要なライブラリのインストール
以下のコマンドを実行して、必要なライブラリを取得してください。
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
を取得する。
ソースコード全文
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
}