LoginSignup
28
4

More than 1 year has passed since last update.

【Rails】Sorcery & Twitter認証で詰まった話

Last updated at Posted at 2022-05-05

はじめに

こんにちは、たけむーです。

今回は、ポートフォリを開発していてtwitterログインの実装で詰まったのでメモとして残しておきます。

アプリ側の設定はSorceryのwikiこの記事を参考にしました。
Twitter Developerの設定はこの記事を参考にしました。

この記事では設定の説明は省略させもらいます。

結論

先に結論を言うと、Twitter Developerでアクセス権限をEssentialからElevatedにしましょうという話です。

発生したエラー

上記の記事等を参考に設定を行い、実際に認証できるか動かしてみました。
すると、以下のようなエラーが出ました。

ActiveRecord::NotNullViolation - PG::NotNullViolation: ERROR:  null value in column "name" of relation "users" violates not-null constraint
DETAIL:  Failing row contains (55, null, null, null, null, 18668cfb-c19d-4d9b-85f3-28ac2719e9a9, 0, 2022-03-19 04:36:58.732046, 2022-03-19 04:36:58.732046, null, null, null, null, 0).:
  app/controllers/oauths_controller.rb:26:in `create_user_from'
  app/controllers/oauths_controller.rb:14:in `callback'

パッと見た感じだと、「UsersテーブルのnameカラムにはNOT NULL制約を付与しているのに、NULLで保存しようとして制約に引っ掛かってるよ」みたいなエラーだと思います。

確かに今回はUsersテーブルのnameカラムにNOT NULL制約を付与しています。

schema.rb
  create_table "users", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", null: false
    t.string "crypted_password"
    t.string "salt"
    t.string "uuid", null: false
    t.integer "role", default: 0, null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

エラーが発生している箇所はoauthsコントローラのcreate_fromの部分です。

class OauthsController < ApplicationController
  skip_before_action :require_login

  def oauth
    login_at(auth_params[:provider])
  end

  def callback
    provider = auth_params[:provider]
    if auth_params[:denied].present?
      redirect_to boards_path, success: t('.success', item: provider.titleize)
      return
    end
    create_user_from(provider) unless (@user = login_from(provider))
    redirect_to foods_path, success: t('.success', item: provider.titleize)
  end

  private

  def auth_params
    params.permit(:code, :provider, :denied)
  end

  def create_user_from(provider)
    @user = create_from(provider) # ←ここ
    reset_session
    auto_login(@user)
  end
end

このcreate_fromでtwitterの情報を使ってユーザーを作成しますが、今回はここで失敗しています。

この時点で、twitterの情報がうまく取得できていないのかなと考えることができます。

試したこと(意味なかった)

  • API keyやAPI Secret keyが設定できているかの確認、念のため再発行した
  • CallbackURLがTwitter Developer側とアプリ側で一致しているか確認
  • 開発環境でhttp://127.0.0.1:3000/にアクセスしているか

他にも今回の認証で触ったファイルでタイポ等がないか何回も確認しましたが、そういったミスは見つかりませんでした。

解決法

色々見たけど、特に原因はわからず...

ふと思った、そもそもcreate_fromって何してるの?
sorceryの定義されている部分を見てみます。
ここで定義されてました。
以下がメソッドの部分です。

def create_from(provider_name, &block)
  sorcery_fetch_user_hash provider_name
  # config = user_class.sorcery_config # TODO: Unused, remove?

  attrs = user_attrs(@provider.user_info_mapping, @user_hash)
  @user = user_class.create_from_provider(provider_name, @user_hash[:uid], attrs, &block)
end

一度、create_fromの前で処理を止めて一つずつ見てみましょう。

    24: def create_user_from(provider)
    25:   binding.pry
 => 26:   @user = create_from(provider)
    27:   reset_session
    28:   auto_login(@user)
    29: end

[1] pry(#<OauthsController>)> provider
=> "twitter"
[2] pry(#<OauthsController>)> sorcery_fetch_user_hash(provider)
=> nil

次に、sorcery_fetch_user_hashの部分を見てみます。

def sorcery_fetch_user_hash(provider_name)
  # the application should never ask for user hashes from two different providers
  # on the same request.  But if they do, we should be ready: on the second request,
  # clear out the instance variables if the provider is different
  provider = sorcery_get_provider provider_name
  if @provider.nil? || @provider != provider
    @provider = provider
    @access_token = nil
    @user_hash = nil
  end

  # delegate to the provider for the access token and the user hash.
  # cache them in instance variables.
  @access_token ||= @provider.process_callback(params, session) # sends request to oauth agent to get the token
  @user_hash ||= @provider.get_user_hash(@access_token) # uses the token to send another request to the oauth agent requesting user info
  nil
end

ひとつずつ見ていきました。
(特に問題なかったので省略させていただきます。)

[4] pry(#<OauthsController>)> sorcery_get_provider provider
省略
[5] pry(#<OauthsController>)> @provider
省略
[6] pry(#<OauthsController>)> @provider != provider
省略
[7] pry(#<OauthsController>)> @access_token
省略

問題は次です。

[8] pry(#<OauthsController>)> @user_hash
=> {:token=>*******************************,
 :user_info=>
  {"errors"=>
    [{"message"=>
       "You currently have Essential access which includes access to Twitter API v2 endpoints only. If you need access to this endpoint, you’ll need to apply for Elevated access via the Developer Portal. You can learn more here: https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-leve",
      "code"=>453}]},
 :uid=>""}

本来ならユーザーの情報が格納されていて欲しいのに、エラーメッセージが格納されています。
翻訳してみると、以下のようになりました。

You currently have Essential access which includes access to Twitter API v2 endpoints only. If you need access to this endpoint, you’ll need to apply for Elevated access via the Developer Portal. You can learn more here: https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-leve
現在、Twitter API v2エンドポイントへのアクセスのみを含むEssentialアクセス権をお持ちです。このエンドポイントへのアクセスが必要な場合は、開発者ポータルからElevatedアクセスに申請する必要があります。詳しくはこちらをご覧ください: https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-leve

なるほど。
このメッセージに従って、アクセス権をEssentialからElevatedに変更します。

最初にも載せたこの記事を参考に進めていきます。
Twitter Developerにアクセスすると以下のようになっていると思います。
twitter_elavated.png
右下を見ると、Essentialになっています。
これを先ほどの記事を参考にして設定すると以下のようになると思います。
スクリーンショット 2022-05-05 14.00.09.png
これでアクセス権をElevatedに変更できました。

※申し訳ございませんが、細かいやり方については省略させていただきます。

この状態で再度twitter認証を試したところ成功しました👏
ちゃんとユーザーのデータも作られていました。

補足

Twitter APIを使う際に、利用目的を運営側に伝え審査を受ける必要があります。
これまではネットに転がっていた例文で通っていたのですが、これが2022年4月から厳しくなったようです。
あくまで私の予想なのですが、改正個人情報保護法が関係していると思われます。
何度か運営側と英語でやりとりする必要がありそうですが、そこは各々でがんばってもらえればと思います。
このあたりについては詳しいことが分かれば追記しようと思います。

最後に

今回はこれで以上となります。
調べてもなかなか参考になる記事が出てこなかったので書かせていただきました。
少しでも参考になれば幸いです。

最後まで読んでいただきありがとうございました。

28
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
4