I'm using Devise for authentication in my Rails 3.2 app and am having trouble configuring omniauth-facebook to get the new user's phone number.
First of all: I'm not even sure that it's possible to get a phone number, so if that's the case and someone knows for sure, I'd be happy just for a confirmation.
It doesn't appear from https://github.com/mkdynamic/omniauth-facebook that "phone" is part of the FB auth hash by default, though the general Omniauth schema does have .info.phone (not required, of course). So my first idea was that it's a FB permissions problem. I'm not sure what permissions to use, though, as the Permissions with Facebook Login page doesn't say where to find the phone value (maybe this means it's just not possible?).
I have phone as a required attribute on the User model, so when I try to get it through FB the new object never persists. It works fine without looking for a phone number.
My config file:
# /config/initializers/devise.rb
config.omniauth :facebook, 'FACEBOOK_APP_ID', 'FACEBOOK_APP_SECRET', scope: 'email,public_profile', display: 'page'
In my user model:
# user.rb
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.phone = auth.extra.raw_info.phone # have also tried auth.info.phone
end
end
Thanks in advance for any help you may be able to provide!
There's currently no way to get a user's phone number from Facebook.
Facebook's Graph API reference lists all the user information that you can access via the API. A user's phone number is not on the list.
Also, to inspect the contents of the auth hash, add the following line of code at the beginning of your authentications/sessions/callbacks controller action:
render :text => "<pre>" + env["omniauth.auth"].to_yaml and return
You'll see that there is no phone field at auth.extra.raw_info or auth.info.
Related
I'm using the omniauth-facebook gem with devise to set up Facebook login on my website. I'm at the point of importing Facebook user data into my database, but I'm having some weird issues.
Here's my method used to import the data:
#User.rb
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email.to_s
user.password = Devise.friendly_token[0,20]
user.username = auth.info.name
end
end
The record I get back has a user.username equal to the Facebook email, and the user.email is nil. auth.info.name (which is actually the email address) is the only piece of Facebook user data I'm actually able to recover. Everything else comes back nil.
Has anyone else encountered this?
Why are you using user instead of member inside of the first_or_create block? Is it a typo while creating a code snippet?
Anyway, I believe that the issue is for users that exists in database. In such case block that is passed to the first_or_create method isn't evaluated (yield is only for new records) so fields are not updated.
Make sure that you specified those fields (or didn't specified only name) in omniauth-facebook configuration: https://github.com/mkdynamic/omniauth-facebook. It returns name and email by default.
You should also take a look at the great RailsCasts about Facebook Authentication.
I am now implementing omniauth feature into my app. Everything works fine except that i cant get the first and last name from the facebook. Here is my model code.
def self.from_omniauth(auth)
user = User.where(email: auth.info.email).first
if user
return user
else
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.email = auth.info.email
user.image = auth.info.image
user.password = Devise.friendly_token[0,20]
end
end
I already have the strong parameters setup properly for devise as am using that now for default authentication and is working properly.Is there any additional permissions necessary for first and last name from facebook?
After some fiddling around i found the solution. Now i think we have to explicitly require the fields we require. For me the fix is just to add first_name and last_name to facebook.
In my initializers i added first_name and last_name to info fields.
info_fields: 'email, first_name, last_name'
Update
My full config file will look like this now
config.omniauth :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_SECRET"], scope: 'email', info_fields: 'email, first_name, last_name'
From checking the Facebook docs, the first_name and last_name fields are both part of the public profile so your permissions should be fine.
No idea if this would work (in fact, I would kind of hope it doesn't), but in the implementation we've got working in production at the moment we're using Hash accessors instead of methods. So:
new(
first_name: oauth_data["info"]["first_name"],
last_name: oauth_data["info"]["last_name"],
...
Given your email etc fields are getting set correctly, I'd be surprised if trying that works, but it might be worth a shot.
Failing that, have you got any validations or before_create callbacks which could be interfering somehow?
Ran into this issue while designing the OAuth flow for an app that was using Devise + omniauth-facebook.
Using the public_profile scope, you get back a name attribute on the auth hash.
request.env["omniauth.auth"]
My issue is that a user has one profile and it is autosaved ( user is required to enter a first name and last name at sign up which is validated on the profile model)
Solution: Create a name parsing method in your omniauth services model, which you can pass the request.env["omniauth.auth"]["info"]["name"] as an argument.
# auth hash returns a name like "John Doe Smith"
def parse_name_from_string(ful_name_string)
name_array = name_string.split(" ") # break apart the name
# I chose to return a PORO so i can do something like parsed_user_name_from_facebook_auth.first_name
{
last_name: name_array.pop,
first_name: name_array.join(" ")
}
end
I'm trying to use FB Open Graph to let my app update a user's attribute. I have Koala installed and using facebook-omniauth for my authentication. Simply I would like query my database looking for a user that matches his fb id and if that user does not exist then I would like to update the user model's attributes with data from the facebook API. Also I'm using mongoid as oppose to active record for my database.
In my user model I have this method.
def facebook
#facebook ||= Koala::Facebook::API.new(oauth_token)
end
Within my controller I have these lines of code within one of my methods.
#user = User.where(facebook_uid: params[:auth_id])
if #user.empty?
User.create(
first_name: User.facebook.get_object("name"),
last_name: User.facebook.get_object("email"),
facebook_uid: params[:auth_id],
facebook_oauth_token: params[:auth_token])
else
User.update_attributes(
facebook_oauth_token: params[:auth_token]
end
User.facebook.get_object("email") does not return me a user's email when I play around in my console. Does anybody have any idea how to do so?
Thanks!
This should work:
graph = Koala::Facebook::API.new(oauth_access_token)
profile = graph.get_object('me', fields:'email')
Now profile['email'] will get you the email of the user.
Try this:
facebook = Koala::Facebook::API.new(oauth_token)
public_attributes = facebook.get_object("me")
if public_attributes does not return email, this means that the user has not authorized the email for your App. check that you add "email" scope to the OAuth authorization process. If you use devise, this is the config:
config.omniauth :facebook, "facebook_app_key", "facebook_app_secret", {scope: "email"}
I allow Facebook authentication on my Rails website and use Omniauth for it. I recently received the following error in production:
ActiveRecord::RecordInvalid: Validation failed: Email can't be blank,
Email is invalid
Normally Facebook signup works fine, so what would cause this specific error? Below is my code for creating a User with Omniauth.
def self.create_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.email = auth[:info][:email]
user.password = SecureRandom.urlsafe_base64(n=10)
user.save!
end
end
Actually, there has been a lot of discussion about this issue in the omniauth-facebook repo.
I think the user TeamRainless is the one who got closest to the answer:
Some users have supplied a phone number which facebook uses as it's main authentication method instead of the email address. I believe the phone number is then encrypted and that becomes what the email address would normally be.
The only solution to this problem is to redirect the user to a form where the registration process will be completed. Check out the Railscasts OmniAuth Part 2 episode on how to do this.
Just two failed login attemps hit my mailbox. Looking at the data the problem was found quickly: Facebook is sending a 11 digit number instead of a email address to my Omniauth-Controller. So the User-Model can't be saved, because its created with a email constraint on the column in the migration file.
Anybody has a idea how I should proceed with the data in such cases? I don't really care if the user has a malformed email address, so I could theoretically just change the column to a normal string etc. Are there better solutions?
Bonus Questions:
Any other fields known to be unrelieable with the facebook + omniauth + devise
environment?
Any fields known to be unrelieable with the
google_oauth2 plugin?
I take it you are using a function similar to below...
def self.find_for_facebook_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]
)
end
user
end
Are you sure auth.info.email is mapped to the correct parameter
EDIT:
Since the above is all fine. I guess the two options are remove the contraint as you say or perform your own check for string or that it contains an # or whatever and if the data passed is not the correct format you could insert a dummy email address.
This is how i solved it quick & dirty:
# facebook can send malformed/invalid email
email = auth[:info][:email]
unless email =~ /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})$/i
email = "#{Time.now.to_i}#MALFORMED_EMAIL.com"