Ruby on RailsでOmniAuthを用いてgoogleとgithubの認証やり方完全入門(初心者向け)

# 新規登録やログインをgoogleやgithubのアカウントでできるようにする
### OmniAuthとは
**OmniAuth**は、OAuth認証をシンプルに扱うためのRubyライブラリで、RailsアプリケーションにSNSログイン機能を実装する際に広く利用されています。OmniAuthを使うと、GitHub、Google、Facebookなど、さまざまなプロバイダーを通じての認証が容易になります。

### OAuth認証とは
**OAuth認証**（OAuth 2.0）は、ユーザーが自分のパスワードを第三者に渡さずに、他のサービスにアクセス許可を与えるための認証プロトコルです。OAuthは、特にWebアプリケーションやモバイルアプリケーションにおいて、ユーザーが他のアプリケーションやサービスと安全にデータを共有できるようにするために使われます。


## ①googleのOAuthアプリケーションを作成する
googleのAPIを作成するには<a href="https://console.cloud.google.com/cloud-resource-manager">Google Cloud Console</a>にアクセスし、OAuthアプリケーションを作成します.

作成のやり方は下の記事を参考にしてください.

https://zenn.dev/shunjuio/articles/b9ffb6565b7409

OAuthアプリケーションが作成できたら,クライアントIDとクライアントシークレットをメモしておく.

## ②githubのOAuthアプリケーションを作成する.
<a href="https://github.com/settings/developers">GitHub Developer Settings</a>にアクセスし,OAuthアプリケーションを作成します.

1. ``New OAuth App``をクリックして新しいアプリケーションを作成する.

2. ``Application name``には好きなアプリ名を入れる.

3. ``Homepage URL``にはホームページのURLを入れる.

例　{
開発環境: ``http://localhost:3000``
    本番環境: ``https://your-app-name.herokuapp.com``
}
4. ``Application description``にはアプリの説明を入力する.

5.``Authorization callback URL``はコールバックURLといい,github側で認証が完了したあと,アプリ側に行くとき使われるurlということである.(**これはGETリクエストで処理される(ここ重要)**)

(例)``http://localhost:3000/auth/github/callback``

6.``Enable Device Flow``は**チェックしなくていい**
これでOAuthアプリケーションを作ることができた.

7.``Client secrets``を発行する.

そのあとClient IDとClient secretsメモしておく.

## ③ENVにAPIキーを書き込む
envというファイルをつくる.
```ruby:env
GOOGLE_CLIENT_ID=googleのクライアント ID
GOOGLE_CLIENT_SECRET=googleのクライアント シークレット

GITHUB_CLIENT_ID=githubのClient ID
GITHUB_CLIENT_SECRET=githubのClient secret
```
``env``は**githubにあげないようにする.**

## ④認証に必要なパッケージをインストールする.
```ruby:Gemfile
gem 'omniauth' 

gem 'omniauth-google-oauth2'

gem 'omniauth-github'

gem 'omniauth-rails_csrf_protection'
```
``gem 'omniauth-rails_csrf_protection'``これは**CSRF（クロスサイトリクエストフォージェリ）対策**を強化するための Gemです.(**なくてもいい**)

## ⑤Userモデルにproviderとuidのカラムを追加する
Userモデルに``provider``と``uid``のカラムを追加する.
```
rails generate migration AddProviderAndUidToUsers provider:string uid:string
rails db:migrate
```
``provider``にはGoogleやGitHubのどのサービスを使って認証されたかを保存しておくカラムである.

``uid``はGoogleやGitHubで認証された際、それぞれのサービスがユーザーを一意に識別するためのIDを保存するカラムである.

## ⑥omniauth.rbにOmniAuthの設定を記述する
``config/initializers/omniauth.rb``のファイルにOmniAuthを利用した認証プロバイダ（GoogleやGitHub)の設定を行う.

まずOmniAuthはPOSTリクエストしか受け付けないため,**GETリクエストも受け付けるよう**に設定する.

そしてGETリクエストのときは警告がでるため出ないように設定する.

```config/initializers/omniauth.rb
OmniAuth.config.allowed_request_methods = [:post, :get] #getリクエストもできるようにする
OmniAuth.config.silence_get_warning = true #getリクエストの時の警告をなくす

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], {
    scope: 'email,profile', #OAuthのemailやアイコンのアクセスが求められる
    prompt: 'select_account', #アカウントを選択する
    image_aspect_ratio: 'square', #Googleアカウントのプロフィール画像の比率を「正方形」に設定する
    image_size: 50, #Googleのプロフィール画像のサイズを50ピクセルに設定する
    access_type: 'offline' #リフレッシュトークンを取得する
  }
  provider :github, ENV['GITHUB_CLIENT_ID'], ENV['GITHUB_CLIENT_SECRET'], {
    scope: 'user:email' #OAuthのemailのアクセスが求められる
  }
end
```

 ## ⑥sessions_controller.rbで認証の処理を書く.
 ``sessions_controller.rb``には,認証を受け付けて,認証してきたユーザーがデータベースに存在しなかったらそのユーザーを新規登録して,データベースに存在したらログインさせる処理を書く.
 **(しかし,この処理はUserモデル(user.rb)に書いているのでそのメソットである``from_omniauth``を使うだけ)**
 ``` app/controller/sessions_controller.rb
 class SessionsController < ApplicationController
  def create
    auth = request.env["omniauth.auth"] #OmniAuthによって取得された認証情報が格納されたオブジェクトである.
    user = User.from_omniauth(auth) #from_omniauthメソットに取得したauthを入れる
    if user.persisted? #そのユーザーがもし存在するならsessionにuser.idを入れる
      session[:user_id] = user.id
      flash[:notice] = "ログインしました"
      redirect_to items_path
    else
      flash[:alert] = "ログインに失敗しました: #{user.errors.full_messages.join(", ")}"
      redirect_to login_path
    end
  end
end
 ```
userモデルに処理を書く.パスワードにはランダムに生成された値を入れる.
(パスワードがないと登録できないため)
```user.rb
  def self.from_omniauth(auth)
    user = find_or_initialize_by(provider: auth.provider, uid: auth.uid) #providerとuidからユーザーを検索して存在すればそのデータを取得して,存在しなければ初期化してuserに代入する.
    if user.new_record? #ユーザーが存在しないならば,trueを返す.
      existing_user = find_by(email: auth.info.email) #emailが同じアカウントがないか調べる
      if existing_user #同じアカウントがあったら
        user = existing_user
        user.update(provider: auth.provider, uid: auth.uid)
      else
        user.email = auth.info.email
        user.name = auth.info.name
        user.password = SecureRandom.hex(10)
        user.save
      end
    end
    user
  end
```
 ## ⑦session_store.rbにセッションの処理を書く.
 
 ```config/initializers/session_store.rb
 if Rails.env.production?
  Rails.application.config.session_store :cookie_store, key: '_my_session', expire_after: 1.weeks, domain: 'mydomain.com'
else
  Rails.application.config.session_store :cookie_store, key: '_my_session', domain: 'localhost'
end
 ```
 ## ⑧URLを設定する
 ``` routes.rb
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
 ```
## ⑨アクセスできるようにする 
 ```
<%= link_to "Login with Google", "/auth/google_oauth2", method: :post %>
<%= link_to "Login with GitHub", "/auth/github", method: :post %>
 ```