1

I'm building a social login with Rails, and I've integrated it successfully with Google and Facebook. So, I do the same with Twitter. But I can't redirect to my app after login to Twitter. I received an error like:

ActiveRecord::RecordInvalid in Users::OmniauthCallbacksController#twitter Validation failed: Email can't be blank, Email can't be blank, Email is invalid

This is my code in the controller:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    generic_callback("facebook")
  end

  def google_oauth2
    generic_callback("google_oauth2")
  end

  def twitter
    generic_callback("twitter")
  end

  def generic_callback provider
    @user = User.from_omniauth(request.env["omniauth.auth"])
    if @user.persisted?
      log_in @user
      flash[:success] = t("users.new.welcome")
      redirect_to @user
    else
      flash[:error] = t("sessions.new.error")
      redirect_to root_url
    end
  end

  def failure
    redirect_to root_path
  end
end

A part of code in model to get data

# Generate data from the social
  def self.from_omniauth(auth)
    user = User.where(email: auth.info.email).first
    password = Devise.friendly_token[0,20]
    user ||= User.create!(provider: auth.provider,
                           uid: auth.uid,
                           email: auth.info.email,
                           name: auth.info.name,
                           password: password,
                           password_confirmation: password)
  end

And in file configure devise.rb

config.omniauth :google_oauth2, ENV["CLIENT_ID"], ENV["CLIENT_SECRET"], scope: "email", info_fields: "email,name"
config.omniauth :facebook, ENV["FACEBOOK_ID"], ENV["FACEBOOK_SECRET"], scope: "email", info_fields: "email,name"
config.omniauth :twitter, ENV["TWITTER_ID"], ENV["TWITTER_SECRET"], scope: "email", info_fields: "email,name"
Kiter
  • 11
  • 1
  • 3

1 Answers1

0

By default Devise users require an email. The error you are seeing is the validation failure due to you not receiving an email in the response from Twitter. (You didn't show any of the code for the actual OAuth request, but for the sake of argument I'm assuming that the authentication is successful and you are actually getting a valid response with the redirect back to your app.)

According to the Twitter API docs, requesting a user's email is an elevated permission:

The "Request email addresses from users" checkbox is available under the app permissions on developer.twitter.com. Privacy Policy URL and Terms of Service URL fields must be completed in the app settings in order for email address access to function. If enabled, users will be informed via the oauth/authorize dialog that your app can access their email address.

In addition the documentation states:

If the user does not have an email address on their account, or if the email address is not verified, null will be returned.

So, you need to ensure that your app's permissions are configured correctly to get any emails, and you can't rely on getting an email back even so.

One alternative is to disable the email validation in your Devise user model like so:

class User < ApplicationRecord
  ...
  def email_required?
    false
  end
end

EDIT: The Twitter API requires the caller to also explicitly ask for the account email (passing include_email=true in the request). Looking at the code in omniauth-twitter -- which I assume you are using -- it does do that, so you should get it if your app permissions are configured and the account has a verified email.

rmlockerd
  • 3,776
  • 2
  • 15
  • 25
  • Thank you very much, I'm enabled the 3-legged OAuth of Twitter app and successfully integrated it. – Kiter Aug 01 '21 at 06:31