はじめに
Railsアプリに Googleログイン機能を追加したので、備忘録としてまとめます。
今回は、Devise を導入しているアプリに Googleログイン機能を追加します。
環境
- Ruby 3.3.6
- Rails 7.2
- PostgreSQL
- Devise
- Docker / Docker Compose
大まかな手順は以下です。
- gemを追加する
- usersテーブルにカラムを追加する(
provider,uid) - Userモデルを
omniauthableに対応させる - DeviseにGoogle OAuthの設定を追加する
- Google CloudでOAuthクライアントを作成する
- callback用のコントローラーを作成する
- routesを設定する
- ログイン画面 / 新規登録画面にGoogleログインボタンを追加する
- 動作確認をする
1. gemインストール
gem "omniauth-google-oauth2"
gem "omniauth-rails_csrf_protection"
•omniauth-google-oauth2 は Googleログイン用の gem
•omniauth-rails_csrf_protection は CSRF対策用の gem
gemを追加したらbundle installします。
bundle install
2. usersテーブルに provider と uid を追加する
Googleログインしたユーザーを識別するため、usersテーブルにproviderとuidを追加します。
bin/rails generate migration AddOmniauthToUsers provider:string uid:string
生成されたmigrationファイルを以下のように修正します。
class AddOmniauthToUsers < ActiveRecord::Migration[7.2]
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
add_index :users, [:provider, :uid], unique: true
end
end
migrationを実行します。
bin/rails db:migrate
3. UserモデルをOmniAuthに対応させる
次に、User モデルを Googleログインに対応させます。
app/models/user.rb の devise に、omniauthable を追加します。
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :omniauthable, omniauth_providers: %i[google_oauth2]
追記した内容
:omniauthable, omniauth_providers: %i[google_oauth2]
何をしているか
• :omniauthable
OmniAuthを使った外部認証を有効にする設定です。
• omniauth_providers: %i[google_oauth2]
使用する外部認証プロバイダを指定しています。
今回は Googleログインのみ追加するので google_oauth2 を指定しています。
4. DeviseにGoogle OAuthの設定を追加する
config/initializers/devise.rb に Google OAuth の設定を追加します。
config.omniauth :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"]
何をしているか
• :google_oauth2
Googleログインを使う設定です。
• ENV["GOOGLE_CLIENT_ID"]
Google Cloud で取得した Client ID を読み込みます。
• ENV["GOOGLE_CLIENT_SECRET"]
Google Cloud で取得した Client Secret を読み込みます。
Client ID / Client Secret はコードに直書きせず、環境変数で管理します。
5. Google CloudでOAuthクライアントを作成する
次に、Google Cloud 側で OAuth クライアントを作成します。
Googleログインを使うには、Google Cloud Console で以下の情報を取得する必要があります。
- Client ID
- Client Secret
OAuth 同意画面や OAuth クライアントの作成は、以下の公式ドキュメントが参考になります。
承認済みの JavaScript 生成元
開発環境では以下を追加しました。
http://localhost:3000
承認済みのリダイレクト URI
http://localhost:3000/users/auth/google_oauth2/callback
ポイント
- JavaScript 生成元には オリジンのみ を指定する
- リダイレクト URI には callback の完全URL を指定する
- http/https、ドメイン、ポート、パスは完全一致が必要
本番環境では https:// のURLを使用する必要があるため、
開発用クライアントと本番用クライアントは分けて管理するのがおすすめです。
6. 環境変数を設定する
取得した Client ID / Client Secret は環境変数に設定します。
.env に以下を追加します。
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxxx
Docker を使っている場合、環境変数を変更したあとにコンテナを再作成しないと反映されないことがあります。
その場合は以下を実行します。
docker compose down
docker compose up -d --build
7. callback用のコントローラーを作成する
Google認証後に返ってきた情報を受け取るため、callback用のコントローラーを作成します。
app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
auth = request.env["omniauth.auth"]
user = User.find_by(provider: auth.provider, uid: auth.uid)
if user.nil?
user = User.find_or_initialize_by(email: auth.info.email)
user.provider = auth.provider
user.uid = auth.uid
user.name ||= auth.info.name
user.password = Devise.friendly_token[0, 20] if user.encrypted_password.blank?
user.skip_confirmation! if user.respond_to?(:skip_confirmation!)
user.save!
end
sign_in_and_redirect user, event: :authentication
set_flash_message(:notice, :success, kind: "Google") if is_navigational_format?
end
def failure
redirect_to new_user_session_path, alert: "Googleログインに失敗しました。"
end
end
何をしているか
-
request.env["omniauth.auth"]で Google から返ってきた認証情報を取得 -
providerとuidで既存ユーザーを探す - 見つからなければ
emailで既存ユーザーを探す - 該当ユーザーがいなければ新規作成する
-
sign_in_and_redirectでログイン処理を行う
既存のメールアドレスと一致するユーザーがいた場合は、そのユーザーに Google ログイン情報を紐付けるようにしています。
8. routesを設定する
次に、Google認証後のcallbackを受け取るために routes.rb を設定します。
config/routes.rb の devise_for :users に、OmniAuth の callback controller を追加します。
devise_for :users, controllers: {
omniauth_callbacks: "users/omniauth_callbacks"
}
何をしているか
• devise_for :users
Devise のユーザー認証用ルーティングを定義しています。
• omniauth_callbacks: "users/omniauth_callbacks"
Google認証後の callback を Users::OmniauthCallbacksController で受け取る設定です。
ポイント
この設定を追加すると、Googleログイン用のルートが作成されます。
例えば以下のようなルートが生えます。
• /users/auth/google_oauth2
• /users/auth/google_oauth2/callback
ルートが正しく追加されているかは、以下のコマンドで確認できます。
bin/rails routes | grep google
9. ログイン画面にGoogleログインボタンを追加する
次に、ログイン画面から Google 認証を開始できるように、Googleログインボタンを追加します。
今回は app/views/devise/sessions/new.html.erb に追加しました。
<%= button_to user_google_oauth2_omniauth_authorize_path,
method: :post,
data: { turbo: false },
form: { class: "w-full" },
class: "w-full inline-flex items-center justify-center gap-2 rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50 hover:border-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 transition" do %>
<svg class="h-4 w-4" viewBox="0 0 48 48" aria-hidden="true">
<path fill="#FFC107" d="M43.611 20.083H42V20H24v8h11.303C33.654 32.657 29.195 36 24 36c-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.27 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z"/>
<path fill="#FF3D00" d="M6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.27 4 24 4c-7.682 0-14.347 4.337-17.694 10.691z"/>
<path fill="#4CAF50" d="M24 44c5.17 0 9.86-1.977 13.409-5.193l-6.19-5.238C29.145 35.091 26.715 36 24 36c-5.175 0-9.624-3.332-11.283-7.946l-6.522 5.025C9.5 39.556 16.227 44 24 44z"/>
<path fill="#1976D2" d="M43.611 20.083H42V20H24v8h11.303a12.046 12.046 0 0 1-4.084 5.569l.003-.002 6.19 5.238C37.01 39.171 44 34 44 24c0-1.341-.138-2.65-.389-3.917z"/>
</svg>
<span>Googleでログイン</span>
<% end %>
何をしているか
• user_google_oauth2_omniauth_authorize_path
Google認証開始用のルートです。
• method: :post
POST で認証を開始します。
• data: { turbo: false }
Turbo の影響を避けるために指定しています。
• form: { class: "w-full" }
button_to が生成する form に幅を持たせています。
10. 新規登録画面にもGoogleログインボタンを追加する
ログイン画面だけでなく、新規登録画面にも Googleログインボタンを追加しました。
Google認証では、既存ユーザーならログイン、未登録ユーザーなら新規作成という流れになるため、新規登録画面にも同じ導線を置いています。
11. 動作確認をする
ここまで設定できたら、実際に Googleログインが動くか確認します。
今回は以下の流れで確認しました。
確認したこと
- ログイン画面から Googleログインできるか
- 新規登録画面から Googleログインできるか
- 既存ユーザーに provider / uid が保存されるか
- 未登録ユーザーが新規作成されるか
- 2回目以降も同じユーザーとしてログインできるか
まとめ
今回の実装で、Devise を使った Rails アプリに Googleログイン機能を追加できました。
手順をまとめると以下です。
- gemを追加する
- usersテーブルにカラムを追加する(
provider,uid) - Userモデルを
omniauthableに対応させる - DeviseにGoogle OAuthの設定を追加する
- Google CloudでOAuthクライアントを作成する
- callback用のコントローラーを作成する
- routesを設定する
- ログイン画面 / 新規登録画面にGoogleログインボタンを追加する
- 動作確認をする
既存ユーザーへの紐付けも含めて実装できたので、通常ログインと Googleログインを両立できる形になりました。