👆

Google One Tap を秒で実装する on Rails

2021/11/19に公開

GoogleはOne Tapというサインインサービスを提供している。
ユーザのGoogleアカウントを使って他のサービスにサインインできるようになったりプロフィールを共有したりする。サイトにアクセスしたら右上に出てくるやつ。
それをRailsサービスに最速で導入する手引き。

事前準備

GoogleAPIクライアントIDの取得

公式ドキュメントに従ってGoogle Cloud PlatformでOAuth 2.0 Client IDを作って取得する。公式ドキュメントにもある通り、 Authorized JavaScript originslocalhost も追加する必要があるのが注意点。

One Tap 表示

まずライブラリを読み込む。全ページに表示させるなら application.html.erb に入れておく。

<script src="https://accounts.google.com/gsi/client" async defer></script>

次にOne Tapを表示させるコードを入れる。

<div id='g_id_onload'
  data-client_id='ここにGoogleAPIクライアントIDを入れる'
  data-login_uri='ここにCallBack URLを入れる'
  data-prompt_parent_id='g_id_onload'
  style='position: fixed; top: 76px; right: 16px;'
  data-authenticity_token='<%= form_authenticity_token %>'>
</div>

必須なのはdivのid、クライアントIDそれにCallBack URLだけ。位置を調整するために data-prompt_parent_idstyle を指定している。
ユーザがOne Tapを利用するとCallBack URLにPOSTリクエストが来る。なのでCSRFトークンを渡すために data-authenticity_token も指定しておく。

これでOne Tapが表示される。

CallBack

ユーザがOne TapをクリックしてGoogleによる認証が終わった後にアクセスしてくるCallBackエンドポイントを作る。
必要なのはユーザ情報の取得とその情報を使って登録したりログインしたりする処理。登録やログインは各サービスでまちまちなのでここでは割愛。
送られてくるユーザ情報の認証にはgoogleauthを使うと楽。署名とクライアントIDの両方をチェックしてくれる

class GoogleOneTapController < ApplicationController
  def callback
    payload = Google::Auth::IDTokens.verify_oidc(params[:credential], aud: 'ここにGoogleAPIクライアントIDを入れる')
    
    # 登録・ログイン処理
  rescue Google::Auth::IDTokens::SignatureError, Google::Auth::IDTokens::AudienceMismatchError => e
     # 署名やクライアントIDが不正な場合の処理
  end
end

なお、payloadにはemailやnameが入っている。
cf. クレデンシャル

payload
{
  "iss": "https://accounts.google.com", // The JWT's issuer
  "nbf":  161803398874,
  "aud": "314159265-pi.apps.googleusercontent.com", // Your server's client ID
  "sub": "3141592653589793238", // The unique ID of the user's Google Account
  "hd": "gmail.com", // If present, the host domain of the user's GSuite email address
  "email": "elisa.g.beckett@gmail.com", // The user's email address
  "email_verified": true, // true, if Google has verified the email address
  "azp": "314159265-pi.apps.googleusercontent.com",
  "name": "Elisa Beckett",
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/e2718281828459045235360uler",
  "given_name": "Elisa",
  "family_name": "Beckett",
  "iat": 1596474000, // Unix timestamp of the assertion's creation time
  "exp": 1596477600, // Unix timestamp of the assertion's expiration time
  "jti": "abc161803398874def"
}

参考

Discussion