Omniauth-facebook: retrieve user location - ruby-on-rails

I have the following configuration in my config/initializers/omniauth.rb
provider :facebook, id, secret, {scope: 'email, user_location, user_birthday', image_size: {width: 400, height: 400}}
But the authentication hash does NOT come with user's location information.
I followed the guides and read facebook's documentation, but can't figure out whats wrong. Are there any missing steps?
Does anybody know?

Adding user location to your scope just means your app has the rights to read the user's location. It doesn't mean FB will send it to you. You need to make an FB API call to find it. Check out the Koala gem -- initialize it with the access_token you get from login and then call FB to find the location.

use 'Koala' gem for Request Graph API
and Request with '/me/location'

You must specify exactly which fields should be returned when getting the user's info.
It can be done with info_fields parameter
provider :facebook, id, secret, {
scope: 'email, user_location, user_birthday',
image_size: {width: 400, height: 400},
info_fields: 'email, name, location'
}

Related

Google OAuth 2 redirect_uri_mismatch - OmniAuth Rails app

I've a problem with authenticating Google account with my Rails app.
I'm using omniauth-google-oauth2 gem with Devise.
Always get this Error when I try to access google account:
Error: redirect_uri_mismatch
The redirect URI in the request: http://localhost:3000/users/auth/google_oauth2/callback did not match a registered redirect URI
I'm sure that the registered redirect URI in my google console app is right and identical with requested one, just like that:
so what's main the problem here?
try this way :
add require "omniauth-google-oauth2" to devise.rb in config/initializers folder
add http://localhost:3000/users/auth/google_oauth2/callback into Redirect URL in google API console https://console.developers.google.com
restart server
Mine solution is to force redirect_url in both (code/token) stages, devise.rb initializer:
CALLBACK_URL = 'https://SOMESERVER/users/auth/google_oauth2/callback'
Devise.setup do |config|
config.omniauth :google_oauth2,
"SOMECLIENTID.apps.googleusercontent.com",
"SOMEKEY",
{
:client_options => {:ssl => {:ca_file => 'C:\Ruby21\cacert.pem'}},
:provider_ignores_state => true,
:prompt => "select_account",
:redirect_uri => CALLBACK_URL,
setup: (lambda do |env|
request = Rack::Request.new(env)
env['omniauth.strategy'].options['token_params'] = {:redirect_uri => CALLBACK_URL}
end)
}
end
there is discussion about the issue here: https://github.com/zquestz/omniauth-google-oauth2/issues/181
Be careful of what client id you are setting.
Google API provides two:
Client ID for Google Compute and App Engine
Client ID for web applications
You need to use Client ID for web applications
Make sure you set up the Product Name and Email address via the Consent Screen Link.
Per the omniauth-google-oauth2 documentation you need to:
Go to 'https://console.developers.google.com'
Select your project.
Click 'APIs & auth'
Make sure "Contacts API" and "Google+ API" are on.
Go to Consent Screen, and provide a 'PRODUCT NAME'
Wait 10 minutes for changes to take effect.
I had the same issue, made the updates, waited 10 minutes, still nothing, went to lunch, then it started to work. Guess patience was part of the key to success on this one.

Access Google Plus Contacts google-api-ruby-client and omniauth-google-oauth2

I want to get contact from Google Plus.
I am using
gem "omniauth"
gem "omniauth-google-oauth2"
for authentication and
gem "google-api-client"
for comunicate with google apis.
So far authentication is working fine and I got access_token after authentication.
Now problem is I couldn't find a way to get list of people in my circle (My Google Plus Contact).
Is there any way to do this.
Specifically I need to know is there any gem more like "fb_graph" for google?
I found this trick
https://plus.google.com/u/0/_/socialgraph/lookup/visible/o=%5Bnull%2Cnull%2C%22_UID_%22%5D&rt=j
Just need to put "UID" and you can get contacts in your circle but their name and ID only. But I need more information...
WorkFlow
client = Google::APIClient.new
client.authorization.client_id = GOOGLE_CONFIG[:app_id]
client.authorization.client_secret = GOOGLE_CONFIG[:app_secret]
client.authorization.access_token = token
plus = client.discovered_api('plus')
data = client.execute( plus.people.list, :collection => 'connected', :userId => 'me').data
In data I get this message
<Google::APIClient::Schema::Plus::V1::PeopleFeed:0x6569248 DATA:{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"insufficientPermissions", "message"=>"Insufficient Permission"}], "code"=>403, "message"=>"Insufficient Permission"}}>
I found similar problem here but solution is still needs to be find out.
I need to add Scope in devise initializers and then by auth token everything seems to be working perfectly.
scope: "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
OR Add this line
config.omniauth :google_oauth2, GOOGLE_CONFIG[:app_id], GOOGLE_CONFIG[:app_secret],{ access_type: "offline", approval_prompt: "force", scope: 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile', name: 'google'}

Cannot get oAuth2 Access Token for Google Analytics API

I am using Rails + Garb Gem (Sija Branch) + omniauth-google-oauth2 Gem and I can successfully authenticate with the Google Analytics API and extract data that our app is generating when using a user login, e.g.:
Garb::Session.login('USERNAME', '<PASSWORD>')
I can then use Garb to connect to the Analytics Profile I want and pull the data from it and display some charts on a webpage. This all works fine.
However, I want to use oAuth2 to authenticate with Analytics which is why I had to install the Sija branch of the Garb Gem from Github (it supports oAuth2) and I also installed the omniauth-google-oauth2 Gem. Now in theory I should be able to authenticate using the following code:
Garb::Session.access_token = access_token # an instance of OAuth2::Client
It's at this point that it gets a little hazy for me and I would greatly appreciate some guidance. Here's how far I have gotten:
1) I created a Project in the Google API console and turned on Analytics API under Services
2) This provided me with a Client ID and Client Secret
3) I came across this code which I could populate with the ID and Secret above:
client = OAuth2::Client.new(
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
{
:site => 'https://accounts.google.com',
:authorize_url => '/o/oauth2/auth',
:token_url => '/o/oauth2/token'
})
4) Then there is the next bit of code:
response = OAuth2::AccessToken.new(
client,
STORED_TOKEN, {
refresh_token: STORED_REFRESH_TOKEN,
expires_at: STORED_EXPIRES_AT
})
5) and then in theory connect with:
Garb::Session.access_token = response
The problem I have is I don't have the token information in Point (4) above. It seems to me that with oAuth2 I need to do a "handshake" once and print out the return token values? Perhaps through Rails code which prints the values returned out and then paste the token values into a constant in the Rails app so that I can use them in the above code? I really am confused. As I mentioned earlier, the web app works fine using the user login authentication. All the web app is doing is authenticating with analytics, pulling down some data and drawing a chart. But I am stuck converting it over to oAuth2 as I just do not know how to get the Access Token that the Garb Gem is looking for. I should also note that this is not a public website with multiple users authenticating, this is a CMS website that is connecting to our own Analytics data.
I have seen some partial snippets of aspects of this but not a fully explained or working example. I would really appreciate any guidance and help with this question.
Many thanks in advance,
JR
I've soldiered through this over the last few weeks, so let me share what worked:
To use Oauth2 you need to get a 'refresh token' that you use to 're-authenticate' with google each time you make an API call. The steps for this are as follows:
1) Setup your account in the API console - https://code.google.com/apis/console/b/0/ (seems like you've done that well)
2) In your API account, make sure you have a redirect URI pointing back to your application:
http://some-url.com/auth/google_oauth2/callback
http://localhost:3000/auth/google_oauth2/callback
Note here that google won't let you call back to your local machine as 0.0.0.0:3000... so you'll need to use localhost explicitly
3) In your route file, tie that redirect url to an action in the controller where you're going to create the project or authentication
match '/auth/:provider/callback' => 'authentications#create'
The ':provider' simply lets you match on multiple types of oauth, but you could just put 'google_oauth2' there as well.
4) Now create that action in your controller
def create
auth = request.env["omniauth.auth"]
params = request.env["omniauth.params"]
project = Project.find(params['project_id'])
Authentication.create(:project_id => project.id, :provider => auth['provider'], :uid => auth['uid'], :access_token => auth['credentials']['refresh_token'])
flash[:notice] = "Authentication successful."
redirect_to owner_view_project_path(project)
end
5) The controller action should retrieve the relevant fields from the response object (details of response object here: https://github.com/zquestz/omniauth-google-oauth2) - in particular, you need to get the 'refresh_token' and save that to your project or authentication object - if you haven't added an 'access_token' attribute to the desired object, go do that now with a migration, then start saving the refresh token to that attribute
6) Now when you're ready to call that particular authentication and get API data for it, you can load up that object where you saved the access token, and use that to get a new session with the google API as follows:
#authentication = Authentications.find(params[:id])
client = OAuth2::Client.new GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET,
{
:site => 'https://accounts.google.com',
:authorize_url => "/o/oauth2/auth",
:token_url => "/o/oauth2/token",
}
response = OAuth2::AccessToken.from_hash(client, :refresh_token => #authentication.access_token).refresh!
Garb::Session.access_token = response
#profiles = Garb::Management::Profile.all
What this code did was create an OAuth2 access token (response) by specifying the client and then a refresh_token, then calling 'refresh!' to get a refreshed access token... then use that access token to establish your Garb session, then call down all the profiles for a given account using the Gard::Management::Profile.all
Hope this helps - let me know if you have questions!
Just a note on what worked for me in:
For steps 3, 4 & 5 I used cURL instead to retrieve the Access/Refresh token. Step 6 is then the same for me (using the Sija branch of the Garb Gem). So using cURL:
Using the details associated with your Google app POST the following using cURL:
curl --data "code=<APP_CODE>&redirect_uri=http://localhost:3000/oauth2callback&client_id=<CLIENT_ID>.apps.googleusercontent.com&scope=&client_secret=<CLIENT_SECRET>&grant_type=authorization_code" https://accounts.google.com/o/oauth2/token
The response takes the form:
{
"access_token" : "<ACCESS_TOKEN>",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "<REFRESH_TOKEN>"
}
which you can plug into the Garb Gem as per part 6.
The answer by #CamNorgate is valid.
If you don't have a "refresh_token" back from Omniauth on the callback make sure you are correctly initializing :google_oauth2
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
{ :scope=>"https://www.google.com/m8/feeds, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile",
:approval_prompt=>"force", access_type="offline"
}
end
Make sure to include :approval_prompt=>"force", access_type="offline" in order for the refresh_token to be sent back. The refresh_token is only provided on the first authorization from the user.

Twitter uid is null when using Omniauth (Rails)

I am using Omni auth to authenticate twitter account in my rails application.
I could able to get the uid parameter before, but now its returning null like below
{"provider":"twitter","uid":null,
"info":
{
"nickname":"boobalanv",
"name":"Boobalan",
"location":"",
"image":"<image url>",
"description":"",
"urls":
{
"Website":null,
"Twitter":"http://twitter.com/boobalanv"}},
"credentials":
I am testing this in my local host.
What am i doing wrong or is twitter has stopped providing user id?
Update :
Actually i added client options for authorize path in initializers/omniauth.rb like below
(By doing so only authorization will include prvilege to access direct message)
provider :twitter, Rails.application.config.consumer_key , Rails.application.config.consumer_secret , authorize_params: {force_login: 'true'}, client_options: {authorize_path: '/oauth/authorize'}
only after doing this i am having this issue with uid = null, when i remove this option ' client_options: {authorize_path: '/oauth/authorize'}' its working fine..
any solution for this issue?
Found the answer for this.
The uid field is null when authorize_path is set to "/oauth/authorize".
Instead we can get the Twitter user id by using the below
auth['extra']['raw_info']['id']

OmniAuth - Facebook login not supplying email in user_info

I'm using OmniAuth, and after logging in via Facebook, I get my omniauth.auth key, which looks like this:
user_info:
name: Tim Sullivan
urls:
Facebook: http://www.facebook.com/...
Website:
nickname: ...
last_name: Sullivan
first_name: Tim
uid: "123456789"
credentials:
token: [some token]
extra:
user_hash:
name: Tim Sullivan
timezone: -5
gender: male
id: "123456789"
last_name: Sullivan
updated_time: 2010-12-30T00:52:39+0000
verified: true
locale: en_US
link: http://www.facebook.com/...
email: tim#myemailaddress.com
first_name: Tim
provider: facebook
Now, according to the docs, the email should be in the user_info section, but it isn't. It is, however, in the extra/user_hash section. Since I'm stripping extra, it's not getting stored, so later on down the pipe I'm having problems. I could add it myself, but that doesn't explain why it's not there in the first place.
Why isn't email being put into the user_info section? A bug? Undocumented change?
moved to
email = omniauth["extra"]["raw_info"]["email"]
The hash "info" contains all the information of the User:
email = omniauth["info"]["email"]
I think the doc is not up to date. I usually get it from the extra hash before removing it.
email = omniauth["extra"]["user_hash"]["email"]
While omniauth["info"] used to and should contain the information, I have noticed that facebook seems to be giving me errors with the email which is linked to a facebook bug/(feature?). So I get intermittent errors with this hash where the email is not present which breaks everything.
After much debugging I found that the safest way to not break my code is to call the FB API with Koala or just good ol REST and get the information needed for login if omniauth["info"] does not contain the information you need.
We are using omniauth with the FB JSDK and I couldn't get the email to come back because I had overlooked the fact that FB.login() requires a 'scope' opts.
FB.login(function(response) {
// handle the response
}, {scope: 'email,user_likes'});
After adding the opts (even though the scope was set up on the server) everything was fixed.
https://developers.facebook.com/docs/reference/javascript/FB.login/v2.2#permissions
Since you're using Rails and not JavaScript (another person answered but for JS), you need to specifically ask for email to be returned from the info field hash as it isn't by default. You set this up in your config/initializers/omniauth.rb file like so:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, Rails.application.secrets.omniauth_provider_key, Rails.application.secrets.omniauth_provider_secret,
:scope => 'email', :display => 'popup', :info_fields => 'name,email'
end
This info is kind of hidden at the very end of the Configuring section on the omniauth-facebook gem's GitHub readme.

Resources