【Rails】Sorceryで外部認証 〜Google編〜

# はじめに🧎🏻
現在個人開発しているサービスにて
SorceryのExternalモジュールを利用して外部認証を実装する際に
google認証を実装している例がなかったため、備忘録も兼ねて記します。


※下記の記事にてLINE認証についても解説しています！
内容に一部重複している部分があるため、実装済みの部分に関しては都度読み飛ばしていただければと思います。

https://qiita.com/tarakish/items/a4c73104375878ad61c5

### 環境💻
- Ruby `3.0.1`
- Ruby on Rails `6.1.4.4`
- 【gem】 sorcery `0.16.2`

### 想定読者👥
- sorceryのexternalモジュールをベースとしてgoogle認証を実装したい人

### 前提🎬
- [Simple Password Authentication](https://github.com/Sorcery/sorcery/wiki/Simple-Password-Authentication)でのメールアドレス認証機能は実装済みであること。

# 実装の流れ✔️
少し長い道のりなので全体像を把握しておきましょう。
1. authenticationsテーブルを作成
2. Authenticationモデルの設定
3. OauthsControllerの作成
4. ルーティングの追加
5. Google APIの登録
6. sorcery.rbの設定
7. リンクの設置

この内1~5に関しては、偉大な先人達が記事に残してくれているので割愛します。
自分が主に参考にさせていただいたのは以下の記事です。

- 【1~4】 Externalモジュールの導入部分
https://blog.aiandrox.com/posts/tech/2020/03/29/

- 【5】 Google APIの登録部分
  https://hirocorpblog.com/post-236/
  ※この記事ではローカルホストを指定していますが、本番環境で利用する場合はそのURLも必要です。


5まで終わりましたか？おかえりなさい🍵

それでは`6.sorcery.rbの設定`からやっていきましょう！

### 6. sorcery.rbの設定📝
まず完成形がこちら↓
```ruby:sorcery.rb
Rails.application.config.sorcery.submodules = [:external]

# Here you can configure each submodule's features.
Rails.application.config.sorcery.configure do |config|
    (中略)
    # -- external -- 78行目辺り
    # What providers are supported by this app
    # i.e. [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid, :salesforce, :slack, :line].
    # Default: `[]`
    config.external_providers = %i[google]
    (中略)
    config.google.key = Rails.application.credentials.dig(:google, :client_id)
    config.google.secret = Rails.application.credentials.dig(:google, :client_secret)
    config.google.callback_url = Settings.sorcery[:google_callback_url]
    # config.google.user_info_mapping = { email: 'email' }
    # config.google.scope = 'https://www.googleapis.com/auth/userinfo.email'
    (以下略)
end
```
細かく見ていきましょう。
##### ①モジュールの読み込み
```ruby
Rails.application.config.sorcery.submodules = [:external]
```
externalモジュールを読み込みます。

##### ②providersの指定
```ruby
config.external_providers = %i[google]
```
利用する外部認証のプロバイダーを指定します。

##### ③キー、`callback_url`、取得情報の設定
```ruby
config.google.key = Rails.application.credentials.dig(:google, :client_id)
config.google.secret = Rails.application.credentials.dig(:google, :client_secret)
config.google.callback_url = Settings.sorcery[:google_callback_url]
# config.google.user_info_mapping = { email: 'email' }
# config.google.scope = 'https://www.googleapis.com/auth/userinfo.email'
```
###### a.キーの設定
- `config.google.key`…作成したプロジェクトのクラアントIDを設定
- `config.google.secret`…作成したプロジェクトのクライアントシークレットを設定

上記２つは秘匿情報にあたるため、`credentials.yml`などで管理してください。
```yaml:credentials.yml
google:
  client_id: クライアントidの値
  client_secret: クライアントシークレットの値
```
###### b.`callback_url`の設定
- `config.google.callback_url`…コールバックURLを設定。

開発・本番環境で違うものを設定するため、[Config](https://github.com/rubyconfig/config)ジェムなどで管理すると楽です。
```yaml
# development.yml
sorcery:
    google_callback_url: 'http://localhost:3000/oauth/callback?provider=google'

# production.yml
sorcery:
    google_callback_url: 'https://本番環境のドメイン/oauth/callback?provider=google'
```

###### c.取得情報の設定
- `config.google.user_info_mapping`…名前通り、google認証を通して取得する情報(user_info)を、アプリ側でどのパラメータとして扱うか(mapping)の設定。

- `config.google.scope`…取得する情報のスコープを定める。規定は[公式ドキュメント](https://developers.google.com/identity/protocols/oauth2/scopes#oauth2)に記載されてます。

今回自分の個人開発では、authenticationsテーブルのuidを発行するために外部認証を使用しておりemailや名前は取得しないため、上記2点はコメントアウトしています。
※そのため、ユーザーの情報を取得する場合もしかすると今回の記述では動かない箇所が出てくるかもしれません。ご了承ください🙏🏻

### 7. リンクの設置📌
```erb:user_sessions/new.html.erb
<%= link_to 'Login with Google', auth_at_provider_path(provider: :google) %>
```

# おわりに🙇🏻‍♂️

おそらく機能実装までの過程で間違いなく何かしらのエラーと戦うことになると思います。（自分もそうでした）
本記事でフォローできればよかったのですが、実装から執筆まで期間が空き詳細は忘れてしまったので、
気休め程度に「エラーが出た際はこの辺チェックするといいかもリスト」を置いておきます😶‍🌫️
- Oauth2.0 APIで各環境のURLが正しく設定されているか？（稀に反映に少し時間がかかることもあるみたい）
- パラメータは正しく渡っているか？
- Oauthsコントローラーのストロングパラメータは適切か？
- 本番環境はSSL化されているか？


まだまだ学習中の身のため間違っている点や補足、タイポなどありましたら
お気軽にコメント、編集リクエストいただけますと幸いです！！

# 参考記事📄

https://github.com/Sorcery/sorcery

https://developers.google.com/identity/protocols/oauth2/scopes#oauth2

https://blog.aiandrox.com/posts/tech/2020/03/29

https://hirocorpblog.com/post-236/