前提
GoogleOAuth2.0をある程度知っている
環境
フロント Next.js
バックエンド Go(gin)
OAuth2.0ライブラリ
"golang.org/x/oauth2"
googleOAuth "golang.org/x/oauth2/google"
v2 "google.golang.org/api/oauth2/v2"
結論
フロントからGoogleの認証画面にリダイレクトする際に叩くURLのパラメータを確認する。
access_type=offline
とapproval_prompt=force
をクエリパラメータにつける。
https://accounts.google.com/o/oauth2/auth
?client_id=hogehogehoge
&redirect_uri=http://localhost:3000/login
&response_type=code
&scope=openid email profile
&access_type=offline
&approval_prompt=force
どういうことか
最後のaccess_type=offline
とapproval_prompt=force
がついていないと、Googleの同意画面が簡略化されたものになる。
→ 簡略化というと語弊があるが、ユーザー目線でいうと、アカウント選ぶだけ終わる。
しかし、これらのパラメータがつくと、アカウントを選んだ後にさらに同意画面が出てくる。
→ ユーザー目線では『このアプリを信用しますか?』はいorいいえ 的な選択が挟まる。
いずれの場合も完了後、自分のアプリへのリダイレクト時にcode
は発行される。
しかし、その後のフローとして自身のバックエンドでcode
を使って、認証を行った時のOAuthのレスポンスが異なる。
先述のGoogleの画面でユーザーが同意画面で同意した場合にのみ、リフレッシュトークンを得ることができる。
func (g *GoogleOAuthManager) GetAccessToken(code string) (oAuthInfo *OAuthInfo, err error) {
utils.LogMessage(utils.Debug, "GetAccessToken")
cxt := context.Background()
tokenInfo, _ := g.Config.Exchange(cxt, code)
if tokenInfo == nil {
utils.LogMessage(utils.Error, "failed get google token")
return nil, errors.New("failed get google token")
}
println(tokenInfo.RefreshToken) // ここが空かどうかが変わる
使い道(ただ当たり前のこと書いてます。。。)
バックエンドでユーザーのトークンの期限の管理や認証情報のリフレッシュの制御に合わせて、
細かいカスタマイズが可能。
ユーザー登録の際には同意画面を表示させ、リフレッシュトークンを発行する。
それ以降は、ログイン画面として簡略バージョンの認証画面にしておく。
毎回同意画面を表示させることなく、ボタン一発のスムーズなログインを実現することでユーザビリティに貢献できる。
基本的にアクセストークンはリフレッシュトークンやログインのたびに頻繁に更新するが、
リフレッシュトークンは頻繁に更新するようなものではない。
しかし、セキュリティ上の理由で、ユーザーのリフレッシュトークンごと更新したいケースがあるかもしれない。
バックエンド側で判定ロジックを組めば、意図的にユーザーに同意を求めることができる。
つぶやき
久々に触ったら30分ほど溶かしたので、備忘録を残しておきました。
誰かの役に立てばと。。。
(ネットでいっぱい出てくるけど。)
approval_prompt=force
は古いという情報があるが、私の環境だとこれで動くんだよね。。。なんだろうか。