Fetch Google plus contacts in Rails app - ruby-on-rails-3

I have google login feature implemented in my Rails app and now the scenario is to fetch google plus contacts in my app.
There is one Google Plus gem available but i am not sure whether i can fullfill my requirements using that gem.
Whats the best possible solution to this.
Regards,
Karan

You can use the Google APIs Ruby Client and do something like:
client = Google::APIClient.new
plus = client.discovered_api('plus')
# Code to authorize the client.
...
result = client.execute(plus.people.list,
:collection => 'visible',
:userId => 'me')
Where the code that you need to authorize the client depends on the flow that you are using to implement the login.

I've encounter the same situation, nowhere was clear answer.
What gem you are using for Google Authorization? If you are using omniauth-google-oauth2 here is the solution:
I've found post of a guy who encounter different problem AFTER part of application you are asking for was done, you may find it here - http://blog.baugues.com/google-calendar-api-oauth2-and-ruby-on-rails
Down to the code, this how you callback function in a controller (after logging in) should looks like:
def create #lets say it is session#new controller
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
initial_session(omniauth) unless current_user
client = Google::APIClient.new()
client.authorization.access_token = omniauth["credentials"]["token"]
plus = client.discovered_api('plus')
contacts = client.execute(plus.people.list, :collection => 'visible',
:userId => 'me')
raise contacts.inspect.to_s

Related

Devise/OmniAuth - LinkedIn: Email is blank in callback

I'm using Devise 2.1.2 with multiple OmniAuth providers. My devise.rb file contains this line:
config.omniauth :linkedin, API_KEY, SECRET_KEY, :scope => 'r_emailaddress', :fields => ["email-address"]
It is currently stripped down to just email-address since that is the only thing acting strange. Taking a look inside request.env['omniauth.auth'].info, the email key is blank.
How come? I don't want to bypass validation, I wan't to use the email address from the users LinkedIn account.
Thanks to the thread link in Remus Rusanu's answer, I noticed this post by a LinkedIn employee:
Hey guys, we're working on a migration plan for existing applications. The new member permissions only apply to newly registered applications.
Thanks!
Kamyar
Due to no patience, creating a new LinkedIn application allowed me to retrieve the user email address. How nice that they finally changed their mind about this.
Given that LinkedIn as a matter of policy does not share the email over oauth, I'm not at all surprised.

How do you clear a twitter session in Rails 3 app using devise

I am using the devise, omniauth, omniauth-twitter and twitter gems in a rails 3 app. I want to make it so when a user signs out it also removes the twitter gem configuration. What I'm referring to when I say "twitter gem configuration" is this:
Twitter.configure do |config|
config.consumer_key = YOUR_CONSUMER_KEY
config.consumer_secret = YOUR_CONSUMER_SECRET
config.oauth_token = YOUR_OAUTH_TOKEN
config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
end
If I don't do that and another user logs onto the app from the same computer but doesn't have a user account, they will see the previous user's twitter information. I believe I can remove the configuration by calling
Twitter.reset
I guess my question is where would be the best place to put that? Also if that isn't the best way to remove the user's twitter configuration, how should I do it?
Thanks and let me know if you need any more details.
You can split your configuration into application-specific (which will be global) and client-specific settings. This twitter gem wiki page describes this nicely.
This seems to be working.
In /app/controllers/application_controller.rb you can redirect the default route devise sends the user when they sign_in/out. I'm not sure if this is the "proper" place to put this but it seems reasonable.
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_in_path_for(resource_or_scope)
if current_user.authentications.find_by_provider("twitter")
ckey= YOUR_APPS_CONSUMER_KEY
csecret= YOUR_APPS_CONSUMER_SECRET
auth = current_user.authentications.find_by_provider("twitter")
atoken = auth.token
asecret = auth.secret
Twitter.configure do |config|
config.consumer_key = ckey
config.consumer_secret = csecret
config.oauth_token = atoken
config.oauth_token_secret = asecret
end
end
authentications_path
end
def after_sign_out_path_for(resource_or_scope)
Twitter.reset
authentications_path
end
end
The authentications_path is just the page I'm using to test the authentications and related things. You can redirect anywhere. When a user links an account I save their oauth token and secret in the authentication object. You will need this to access certain aspects of the Twitter gem.
I'll wait a little while to mark this as the answer, see if someone has a better solution.

Rails 3 and Devise: authenticating a user while performing a POST action

Using Rails 3.0.6, Omniauth 0.2.0 and Devise 1.2.1, I'm encountering the following situation:
I want to offer users the option to authenticate via Facebook. I have a user system set up using Devise and I can successfully auth using Facebook. I've spent several hours trying to code the behavior I want for one specific situation:
user is not logged in
user has a site account
user authenticates via Facebook
I offer the user 2 choices at this point
create an account (can be a dummy account with no provided info)
link this Facebook authentication with an existing account
I'm having trouble with the latter option. The user has already authenticated but I still need him to log in with his site account. I have an action in my AuthenticationsController that will associate this authentication with a logged in user. Devise doesn't seem to offer a way for me to log the user in while staying in the same action, though. This was my first attempt to do this
class AuthenticationsController < ApplicationController
before_filter :authenticate_user!, :only => :auth_link_existing_user
...
def auth_link_existing_user
...
end
However, using this method, if the user logs in, they're simply redirected to my site's root page. I know I can change Devise's sign-in redirect, but that will be for all sign-ins. I wanted only this situation to have a separate redirect.
After reading through this mailing list question, I tried to extend SessionsController with my own custom behavior:
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
if params[:redirect] #new
redirect_to params[:redirect].to_sym #new
else
respond_with resource, :location => redirect_location(resource_name, resource)
end
end
This doesn't work either. I've defined my auth_link_existing_user route to use a POST verb (which seems accurate) and redirects can only be GETs.
So now I do have a solution in mind: copy and paste code from Devise's authenticate_user! helper into a new function which can be called within a controller action without redirecting. This seems less than ideal to me because it's duplication of code and increases coupling--a Devise or Warden update that changes this behavior will break my code as well.
Has anyone else tried something like this and come up with a more elegant solution? Do you see a simpler way for me to offer this or similar behavior to my users?
UPDATE: For anyone who wants to use my dirty solution at the end, this is what I did:
def auth_link_existing_user
# FROM Devise/sessions/create
resource = warden.authenticate!(:scope => :user, :recall => "registrations#auth_new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(:user, resource)
# method defined in Ryan Bates' Railscast for Omniauth w/Devise
current_user.apply_omniauth(session[:omniauth])
current_user.save
end
note that this action MUST be placed in your sessions controller. If not, Warden will give you an "invalid email/password" error. It was an incredibly long debugging process to find the source.
With this in place, I use a login form to submit to this action after the user has authenticated.
I like how clean your solution is, though it goes deeper into the stack.
Here is how I've implemented something similar by following the Devise+Omniauth Facebook example on the Devise wiki and modifying the facebook method to pass on the session information to the Login form, with something like this:
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_session_url
end
Then, in your case, I'd check in Login controller action for session["devise.facebook_data"], submit the uid + token with the form and apply_omniauth if present.

OmniAuth dynamic callback url to authenticate particular objects instead of current_user

Say I have the models User and Project. Users and projects are HABTM-associated. My setup is actually a bit more complicated than this, but I think for the purposes of my question this will do.
Now, I want to use omniauth to authenticate a particular project with Twitter, Facebook, what have you. I've figured out how to define my omniauth path_prefix, but I don't know how I could pass in a variable like so: config.path_prefix = 'projects/:project_id/auth', much less make a custom callback url like project/:project_id/auth/twitter/callback.
This will break in production. In development you can get away with a session variable. But in production you need to have the callback url contain your project_id as it could be 2 or more register with different auth_project_id's and then you have no way of knowing which one is called afterwards (the callback is asynchronous).
https://github.com/mkdynamic/omniauth-facebook#custom-callback-urlpath
something like config.path_prefix = "projects/#{#project.id}/auth" might work. I'm testing a similar situation right now.
For posterity's sake, I solved it this way:
I added an auth method to my projects controller, which set a session variable session[:auth_project_id] and then redirectes to auth/ + params[:provider].
In my callback controller authentications, I got my project with #project = Project.find(session[:auth_project_id]), created the authentication, and then session[:auth_project_id] = nil to unset the session variable.
I have done similar thing with devise omniauthable, You can pas any parameter with link. like
<%= link_to "Add twitter Account", user_omniauth_authorize_path(:twitter, params: { project_id: #project.id }) %>
Then in your callback controller
before_action :set_project, only: [:twitter]
def set_project
#project = Project.find(request.env['omniauth.params']['project_id'])
end
Note: Do NOT use request.env['omniauth.auth']

Rails 3 App: for oAuth-only sign-in using Facebook and Twitter, should I use Devise/OmniAuth, or just OmniAuth?

I'm creating a new Rails 3 app and I want to allow users to sign-in using their Facebook or Twitter credentials.
I don't know whether I should implement this using Devise and OmniAuth, or just OmniAuth. I just watched Ryan Bate's screencast on Simple OmniAuth and it seems like I could just use OmniAuth, but I'm not sure it's enough.
I have the following requirements:
Allow sign-in via Facebook and/or Twitter. I will not be implementing local user accounts/passwords.
Signing in via FB/Twitter for the first time should create a new user in the db so I can store the associated FB/Twitter oAuth tokens.
Users should be able to associate both a FB and a Twitter acct to their profile/user so they can post to both FB and Twitter.
Users should be able to delete their account.
I posted this on the Devise Google Mailing List and got this response from José Valim (Devise maintainer and Rails core team member):
"You can use just OmniAuth. If you use Devise, the only benefit is that it will add Omniauth url helpers, but that is so minimal that honestly is not worth the overhead."
-- José Valim
Devise is a fancy way to automatically handle all the things that go with user accounts. If you don't need all the bells and whistles, you should definitely just go the Simple OmniAuth way like in the screencast.
The only hitch I see with trying to link up a Facebook and Twitter account is that you'll have to require them to be signed into one in order to link the other -- and if they do happen to sign in on separate occasions, you could possibly have two Users in your database. This wouldn't be a problem if you were doing Google and Facebook because they both send back an email address, but Twitter only sends back a username, no email address.
You'll have to add a field to the User model for a username (Twitter) and email address (Facebook) so you can attempt to link the accounts if a visitor did it separately and wants to link them later. Just be careful of that when you set it up.
If you can't use just OmniAuth, maybe because, like in my case, you want to use ActiveAdmin which depends on Devise and methods like current_user would conflict, you can just override the login page with your own:
match '/users/sign_in', :to => "sessions#new"
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
I have a "Sign in with Facebook" link in my nav, but this page is necessary for redirecting users when they're trying to access a protected page while not logged in.
Edit: Actually, there is a section on the wiki page: "Using OmniAuth without other authentications"