In my rails 6 app, users have to sign in with twitter omniauth and devise. I have been able to implement it by following this tutorial.
The issue I have is that when a user revokes my app permissions from their twitter account, the omniauth access tokens and access secrets that I previously saved into my database becomes invalid. If the same user decides to re-authenticate, the user gets access to the app but the user's tokens are not updated in the database, rendering the existing tokens invalid.
My question is, how do I continuosly update the user columns in my database so I continue to receive valid access tokens from twitter, especially when the user has access tokens.
This is relevant code from my 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.name = auth.info.name
user.username = auth.info.nickname
user.location = auth.info.location
user.access_token = auth.credentials.token
user.access_secret = auth.credentials.secret
end
end
My user controller looks like this
def twitter
#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: "Twitter") if is_navigational_format?
else
session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
redirect_to new_user_registration_url
end
end
Find the user.
If no user - create user.
Update user (bothe exisitng and new) with fresh omniauth data
Something like this should do the job:
def self.from_omniauth(auth)
#find from omniauth
user = User.where(email: auth.email).first
#find or create
user ||= User.create(
email: data["email"],
password: Devise.friendly_token[0, 20]
)
#update with fresh data
user.name = auth.info.name
user.image = auth.info.image
user.expires = auth.credentials.expires
user.refresh_token = auth.credentials.refresh_token
end
I got it working with by using find_or_initialize_by
def self.from_omniauth(auth)
user = find_or_initialize_by(provider: auth.provider, uid: auth.uid)
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.name = auth.info.name
user.username = auth.info.nickname
user.location = auth.info.location
user.access_token = auth.credentials.token
user.access_secret = auth.credentials.secret
user.save!
return user
end
Related
Since two days i tried to make Login with Facebook on ruby on rails using devise but it returns me NULL as email's value. I read many articles on stackoverflow but a lot of them are from years ago and none have worked for me. Thanks you for helping.
Here is the message in my console when i choose my facebook account
def self.from_omniauth(auth)
unless auth.info.email
auth.info.email = "#{auth.info.name.split(' ').join}#facebook.com"
end
user = User.where("email= ?", auth.info.email).first
puts auth.info.picture
puts auth.info.name
puts auth.info.email
if user
return user
else
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.name = auth.info.name # assuming the user model has a name
# user.image = auth.info.image # assuming the user model has an image
# If you are using confirmable and the provider(s) you use validate emails,
# uncomment the line below to skip the confirmation emails.
user.skip_confirmation!
user.uid = user.uid
user.provider = user.provider
end
end
Using google oauth for a project. Had it working, but wanted to pull the profile picture to display in my app. Once I was able to display the picture, I logged out and tried to relog back in with the oauth. It is now telling me that the name and email have already been taken. I am using a find_or_create_by in my User model to find or create by the oauth credentials. I don't know what is causing this as it was working just a bit ago. And now, when I go back to how my code first was, it is not working period. Just giving me the errors bc of validations(trying to create a record instead of finding the record in the database.)
sessions#create
def create
if params[:provider].present?
#user = User.find_or_create_from_auth(request.env['omniauth.auth'])
if #user
session[:user_id] = #user.id
flash[:notice] = "Logged in as #{#user.name}"
redirect_to dashboard_path
end
Users model-
def self.find_or_create_from_auth(auth)
find_or_create_by!(provider: auth.provider, uid: auth.uid, password_digest: 'N/A') do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.address = "123 ABC St"
user.password = 'n/a'
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save
end
end
Appreciate any help, just not seeing the disconnect here.
This line:
find_or_create_by!(provider: auth.provider, uid: auth.uid, password_digest: 'N/A') do |user|
You only are considering the uid, provider and password_digest. But as your error says the name and email have already been taken. Which means that at your users database you have a unique constraint in both. So even when the uid and provider are different, you can't persist a new instance at DB if it matches with another existing record.
So you can remove the unique constraint or add that validation to find_or_create_by
I have been using omniauth, based off of tutorials similar to this: https://coderwall.com/p/bsfitw#
In this tutorial, and many others, you are instructed to find a user matching what you get back from omniauth, usually like so
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url
end
end
class User < ActiveRecord::Base
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
end
end
So... what is to stop someone else from just posting :provider => "twitter", :uid => "Someone elses uid" to log in as them?
So after talking to a couple people, it appears the reason is because the omniauth.auth variables are passed via environment variables set by the omniauth middleware, not passed in directly from the request.
I am using Omniauth-facebook gem from Github from Ruby on Rails. I have several questions regarding the omniauth-facebook gem.
I am using the following function get the data from Facebook, but this function is called every time the user signs in and in registration.
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.id = auth.uid
user.uid = auth.uid
user.name = auth.info.name
user.username = auth.info.nickname
user.email = auth.info.email
user.gender = auth.extra.raw_info.gender
user.is_admin = false
user.picture = "http://graph.facebook.com/#{auth.uid}/picture?type=large&height=324&width=580"
user.updated_at = auth.extra.raw_info.updated_time
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
How can I differ the registration and login function from each other?
On the other hand, I want to post the user's wall something when the user signs in, or posts something. How can I do it in Omniauth-facebook gem?
Thank you.
Omniauth-facebook gem is best if want to add any post on users wall u can refer this link
facebook share
I ve installed the gem koala and omniauth.
In my user model
class User < ActiveRecord::Base
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.image = auth.info.image
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
def facebook
#facebook ||= Koala::Facebook::API.new(oauth_token)
end
end
Ive the permission from the facebook but still i am not being able to get the relationship status?
Try this
#facebook.get_object('me',:fields=>"name,gender,relationship_status")