Input中心のブログ

GoでGoogleのOauth2をたたくときにはまったことメモ

November 25, 2020

golangでOauth2を使おうと思った時は、oauth2が有名なのでこれは押さえとけばOK. 基本的にはexampleに載ってるけど、嵌ったポイントがあったので次に調べずに済むようにメモしてます.

import (
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

func newConf() *oauth2.Config {
	return &oauth2.Config{
		ClientID:     os.Getenv("OAUTH_CLIENT_ID"),
		ClientSecret: os.Getenv("OAUTH_CLIENT_SECRET"),
		RedirectURL:  os.Getenv("OAUTH_REDIRECT_URL"),
		Scopes: []string{
			"https://www.googleapis.com/auth/userinfo.email",
		},
		Endpoint: google.Endpoint,
	}
}

conf := s.newConf()
// ここでリクエスト先のURLを作成する.
// 注意ポイントとしてはAccessTypeOfflineを設定しておかないと、refresh_tokenは発行されない.
// デフォルトではAccessTypeOnlineになっているらしい
url := conf.AuthCodeURL(os.Getenv("OAUTH_STATE"), oauth2.AccessTypeOffline)

// いったんここでアクセスするとリダイレクトURLに飛ばされる.
// リダイレクトURLで渡される"code"と"state"は必要なので押さえておく
// "scope"も一緒に渡されるけど、必要かは要調査

// 普通にサーバとして開発するなら、ここから下は別のメソッドになるはず

// stateが自分で用意したstateと同じかのチェック
// csrf攻撃対策に必要らしい.stateはランダムな値で用意する.
if req.State != os.Getenv("OAUTH_STATE") {
  return fmt.Errorf("request is something wrong")
}

// "code"からaccess_tokenを発行する.
// refresh_tokenが来ている場合もtokの中に入る
conf := s.newConf()
tok, err := conf.Exchange(ctx, req.Code)
if err != nil {
  return err
}

// tokからclientを作って、このクライアントを使ってリクエストを送る.
// 後は普通のhttp.Clientと同じような使いかたになりそう.
client := conf.Client(ctx, tok)
resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
if err != nil {
  return err
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
  return err
}
fmt.Println(string(body))
return
}

ここからは普通にメモ

refresh_tokenって何?

refresh_tokenaccess_tokenよりも有効時間が長いトークン. refresh_tokenによって、access_tokenを発行する. 実際にリクエストを送るときはaccess_tokenを用いて送る. 上の例に出てきた client を使うと勝手に access_token を更新してくれるみたい.

注意点

refresh_tokenは最初のログインの時しか返してくれない.(refresh_tokenは有効時間が長いので発行しすぎは注意しなければならないから) もし、開発時にrefresh_tokenを発行しなおさないといけないってなったら、以下のリンクにアクセスして、permissionを消すとまた発行しなおされる.

https://myaccount.google.com/u/0/permissions?pli=1

id_tokenとは何か

上の例で言うと conf.Exchange したときに、id_tokenが一緒に返ってきているみたい. id_tokenはOpenIDのtoken. OpenIDはユーザーの認証とかに使われるもので、ユーザーの本人認証とかを出来るらしいけど、正直よく分かってない. Goで使う場合は、go-oidcというライブラリを別途使う必要がある.