【Rails】DeviseとOmniauthを使ってGoogle、Twitter、Facebook認証

DeviseとOmniauthを使って、Railsアプリにソーシャルログイン機能を実装する方法をまとめます。
例えばGoogleログインだけを使いたい場合は、TwitterとFacebook用の記述は無視してください。

## Deviseをインストール
```rb:Gemfile
gem 'devise'
```
```zsh
$ bundle install
$ rails g devise:install
```
```config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```
```erb:app/views/layouts/application.html.erb
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
```

## Modelを作成
```zsh
$ rails g devise User
$ rails db:migrate
```
```config/routes.rb
Rails.application.routes.draw do
  devise_for :users # 自動で追加される
end
```

## Viewを作成
```zsh
$ rails g devise:views users
```

## ログインしないとアクセスできないようにする
```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end
```

ここまでできたらサーバーを再起動。
ログインページや新規登録ページ以外にアクセスしたらログイン画面に飛ばされること、
/users/sign_upにアクセスして、ユーザー登録ができることを確認。

## 環境変数を設定
```rb:Gemfile
gem 'dotenv-rails'
```
```zsh
$ bundle install
$ touch .env
```
```bash:.env
HOST='hogehoge.com'
TWITTER_API_KEY=
TWITTER_API_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
FACEBOOK_KEY=
FACEBOOK_SECRET=
```
IDやSECRET等はあとで取得するので、今は空でOK。

## omniauth系のgemをインストール
```rb:Gemfile
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'omniauth-google-oauth2'
```
```zsh
$ bundle install
```

## Userテーブルにomniauth用のカラムを追加
```zsh
$ rails g migration AddOmniauthToUsers provider:string uid:string
$ rails db:migrate
```

## initializerを編集
```config/initializers/devise.rb
config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], scope: 'email', info_fields: 'email', callback_url: "#{ENV['HOST']}/users/auth/facebook/callback"
config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET'], scope: 'email', oauth_callback: "#{ENV['HOST']}/users/auth/twitter/callback"
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], scope: 'email', redirect_uri: "#{ENV['HOST']}/users/auth/google_oauth2/callback"
OmniAuth.config.logger = Rails.logger if Rails.env.development?
```

## OmniauthCallbacksControllerを作成
```zsh
$ mkdir app/controllers/users/
$ touch app/controllers/users/omniauth_callbacks_controller.rb
```
```controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    callback_for(:facebook)
  end

  def twitter
    callback_for(:twitter)
  end

  def google_oauth2
    callback_for(:google)
  end

  # common callback method
  def callback_for(provider)
    @user = User.from_omniauth(request.env["omniauth.auth"])
    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
    else
      session["devise.#{provider}_data"] = request.env["omniauth.auth"].except("extra")
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end
```

## Userモデルを編集
```app/models/user.rb
class User < ApplicationRecord
  # デフォルトの設定に、:omniauthable以下を追加
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :omniauthable, omniauth_providers: %i[facebook twitter google_oauth2]
  # omniauthのコールバック時に呼ばれるメソッド
  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
    end
  end
end
```

## ルーティングを編集
```config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
  #省略
end
```

## ログイン画面、サインアップ画面を確認
ソーシャルログイン用のリンクが追加されていることを確認します。
![ 2020-12-25 12.27.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/1f74b3f9-0771-ef25-876d-a13f0d08177e.png)
![ 2020-12-25 12.27.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/dbe834cf-0e13-b1e7-5fb8-d48cc99a2e4d.png)



## プラットフォームごとの設定

### Twitter
以下の記事等を参考に、Twitter Developersで`API key`と`API key secret`を取得して、`.env`にセット。
https://dev.classmethod.jp/articles/twitter-api-approved-way/

```bash:.env
TWITTER_API_KEY='hogetwkeyhoge'
TWITTER_API_SECRET='fugatwsecretfuga'
```
そして`Edit authentication settings`をいじって、`アプリのドメイン/users/auth/twitter/callback`をセットして完成。
![ 2020-12-30 18.21.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/ba12f573-3b72-221e-1735-e8a36ab026c8.png)

### Google
この辺の記事を見ながらGCPでアプリを作成し、`クライアント ID`と`クライアント シークレット`を取得して、`.env`にセット
https://qiita.com/nakanishi03/items/2dfe8b8431a044a01bc6#google

```bash:.env
OOGLE_CLIENT_ID='hogehogehoge.apps.googleusercontent.com'
GOOGLE_CLIENT_SECRET='dgpV8aMmmDzfugafuga'
```
`承認済みのリダイレクト URI`に`ドメイン/users/auth/google_oauth2/callback`をセット。
![ 2020-12-30 18.38.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/eab99465-43c5-e187-3468-868abdfce28f.png)

### Facebook
`AppID`と`AppSecret`を取得して環境変数にセット。

```bash:.env
FACEBOOK_KEY='foobarsdsfe'
FACEBOOK_SECRET='bazdejnerf'
```
`Valid OAuth Redirect URIs`に`ドメイン/users/auth/google_oauth2/callback`をセット。

## 参考
- [[Rails] Facebook/Twitter/Googleでのユーザー登録をDevise & Omniauthを使って爆速で実装する - Qiita](https://qiita.com/kazuooooo/items/47e7d426cbb33355590e)
- [RailsでFacebookとGoogleのOAuth連携。SNS認証の方法 - Qiita](https://qiita.com/nakanishi03/items/2dfe8b8431a044a01bc6)