Cookie Overflow with Twitter sign in - ruby-on-rails

I've got he kind of error when I tried to sign in with twitter on my website.
ActionDispatch::Cookies::CookieOverflow in Users::OmniauthCallbacksController#twitter
ActionDispatch::Cookies::CookieOverflow
I can't find a solution, this is the code I use.
omniauth_callbacks_controller.rb
def twitter
#user = User.find_for_provider_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication
set_flash_message(:notice, :success, :kind => "twitter") if is_navigational_format?
else
session["devise.twitter_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
devise.rb
require "omniauth-twitter"
config.omniauth :twitter, 'xxxxxxx', 'xxxxxxxxxxxk', :strategy_class => OmniAuth::Strategies::Twitter
user.rb
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
def self.find_for_provider_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20],
invite_code:"42TXP"
)
end
user

Use: .except("extra")
session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
It removes a big part from the cookie that is simply not needed.

It is what you put in the session in the else part of save
session["devise.twitter_data"] = request.env["omniauth.auth"]
It's probably too big for a cookie.
You should save that information somewhere else. Or don't keep it.

I recently had a similar problem after following the method in https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview, I hope this can help you.
In the OmniauthCallbacksController, instead of:
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
I use:
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"].provider, request.env["omniauth.auth"].uid, request.env["omniauth.auth"].extra.raw_info.name, request.env["omniauth.auth"].info.email, current_user)
In the user model :
def self.find_for_facebook_oauth(provider, uid, name, email, signed_in_resource=nil)
user = User.where(:provider => provider, :uid => uid).first
unless user
user = User.create(:name => name,
:provider => provider,
:uid => uid,
:email => email,
:password => Devise.friendly_token[0,20]
)
end
return user
end
Also in OmniauthCallbacksController make sure you avoid using request.env["omniauth.auth"], use request.env["omniauth.auth"].uid instead.

Related

Login with Facebook when user is registered, Rails 5, Omniouth with Device

I have this User model:
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]
user.fname = auth.info.name
user.skip_confirmation!
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] &&
session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
and this omniouth_callbacks_controller:
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
#user.confirmed_at = Time.now
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Facebook") if
is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
Everything works, but if user is registered without Facebook and then try to login with Facebook, it is not logged, because there are user row in the table in the database.
I want if user is registered in the site without socials and login with Facebook, to do that and site profile to be connected with Facebook profile.
Is there Omniouth method builtin for this case ?
If not, how to do it ?

Omniauth redirects back to signin page

So I'm trying to integrate Google OAuth2 with devise in my app but after signing in and allowing access to the app I get redirected back to the sign in page for some reason. I'm using the following tutorial:
https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application
Here are my files:
callbacks_controller.rb
class CallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.google_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
route.rb:
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
users.rb:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
devise.rb:
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], callback_url: ENV['GOOGLE_CALLBACK_URL']
What am I doing wrong? Thanks
Try this:
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
# return path you want to go to...
end
end

How to save the request.referrer for facebook omniauth in Rails 4

I have two facebook buttons in my application. One on users/sign_up and other on /visitors/owner-faq. I want to save the request.referrer in order to know from which page the user has signed up. I had implemented the same for external signup(which uses a form) and it worked. Now I'm unable to implement the same for facebook omniauth.
Code:
#user.rb
def self.from_omniauth(auth)
email = auth.info.email
user = User.find_by_email(email) # first tries to find an existing user who signed up normal way with the same email to sign them in
if user && user.confirmed?
user.provider = auth.provider
user.uid = auth.uid
return user
end
where(provider: auth.provider, uid: auth.uid).first_or_create do |user| # then tries to find the user who authenticated through FB, and if
user.email = auth.info.email # not present, creates that user
user.password = Devise.friendly_token[0,20]
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.social_photo_url = auth.info.image
user.skip_confirmation!
end
end
#users/omniauth_callbacks_controller
def facebook
#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 => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
Rails.logger.info(#user.errors.inspect)
redirect_to new_user_registration_url
end
end
#application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :store_referrer_url, :only => [:new]
private
def store_referrer_url
session[:referrer] = URI(request.referer).path
end
end
Attempt #1:
I managed to save the request.referrer like this in users/omniauth_callbacks_controller
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
#user.referrer_url = session[:referrer] #here
#user.save!
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
Rails.logger.info(#user.errors.inspect)
redirect_to new_user_registration_url
end
end
But the problem here is the value of referrer_url is overwritten when the existing user logs in from another page. I don't want to get the referrer_url to be overwritten.
Attempt #2:
I tried to save the request.referrer in the from_omniauth(auth) method User model like this
def self.from_omniauth(auth)
email = auth.info.email
user = User.find_by_email(email) # first tries to find an existing user who signed up normal way with the same email to sign them in
if user && user.confirmed?
user.provider = auth.provider
user.uid = auth.uid
return user
end
where(provider: auth.provider, uid: auth.uid).first_or_create do |user| # then tries to find the user who authenticated through FB, and if
user.email = auth.info.email # not present, creates that user
user.password = Devise.friendly_token[0,20]
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.social_photo_url = auth.info.image
user.referrer_url = session[:referrer]
user.skip_confirmation!
end
end
But it gave me this error
undefined local variable or method `session' for #<Class:0x0000000e1c46f8>
Any suggestions would be greatly helpful.
If you want the referrer_url property to stay the same after it's first set, you should use the OR Equal operator, that will only set the value if it's currently nil or false:
#user.referrer_url ||= session[:referrer]
If I understand correctly, your facebook callback is called both on sign up and login, and of course the value would be overwritten. OR Equals will prevent the value from being overwritten once it's set.
Regarding Attempt #2, the session hash is only available in the controller and the view, so you can't use it in the model.
Another possibility:
You are setting session[:referrer] in your store_referrer_url method which is called in a before_filter callback on the new method.
Most likely your login is also made with a new method (for example, with Devise it would be in SessionsController), so the callback is called again and the value is overwritten (all Devise controllers inherit from your ApplicationController). In this case, you could take out the before_filter callback out of the ApplicationController to the controller where you are handling signing up (would be RegistrationsController with Devise).

How to bypass Twitter omniauth "email can't be blank" error?

I am having a little trouble with Twitter authentication. I keep getting the email can't be blank, and redirect to sign up, but after inserting email and clicking sign up, I still get the same error. I tried making it unneeded, but I get the error saying that someone with "" email exists already.
Thanks.
Devise Routes.rb
def has_role?(role)
return true;
end
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.username = auth.info.nickname
end
end
def self.new_with_session(params, session)
if session["devise.user_attributes"]
new(session["devise.user_attributes"]) do |user|
user.attributes = params
user.valid?
end
else
super
end
end
def password_required?
super && provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
end
Call Back Controller
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :twitter, :all
end
You can define username to be your "authentication key" instead of email by
uncommenting this line
config.authentication_keys = [ :email ]
in config/initializers/devise.rb
and changing it to
config.authentication_keys = [ :username ]
i also had the same problem.
this error arises due the fact that in devise User model Email field is set to NotNull.
Solutions:-
1.Set email field in devise to allow null values.
2.so i had saved the email from twitter in my devise email field this is the code for twitter
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
temp = Tempfile.new([auth["uid"], ".jpg"])
temp.binmode
temp.write(open(auth["info"]["image"]).read)
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20],
image:temp
)
user.build_profile(name:user.name,image:temp)
user.profile.save
end
user
end

Link facebook to existing account / omniauth

Simple as that, I want to link to an existing user account his facebook profile (giving priority to the email that has originally registered with) in my rails app, using omniauth and devise.
I have read this but wasn't much helpful to me.
My current structure is like this one.
Below is an example of how I implemented this. If the user is already signed in, then I call a method that links their account with Facebook. Otherwise, I go through the same procedure outlined in the Devise-Omniauth wiki page.
# users/omniauth_callbacks_controller.rb
def facebook
if user_signed_in?
if current_user.link_account_from_omniauth(request.env["omniauth.auth"])
flash[:notice] = "Account successfully linked"
redirect_to user_path(current_user) and return
end
end
#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: "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
# app/models/user.rb
class << self
def from_omniauth(auth)
new_user = where(provider: auth.provider, uid: auth.uid).first_or_initialize
new_user.email = auth.info.email
new_user.password = Devise.friendly_token[0,20]
new_user.skip_confirmation!
new_user.save
new_user
end
end
def link_account_from_omniauth(auth)
self.provider = auth.provider
self.uid = auth.uid
self.save
end

Resources