0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

ソースの流れとOAuthについて

最後に全文載せてるので使ってください。
たぶんほぼそのまま動くと思います。

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

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

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

メソッドの説明

NewGoogleOAuthManager(redirectURL string) *GoogleOAuthManager

環境変数から ClientIDClientSecret を取得し、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
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?