New LinkedIn Permissions Problems (Rails omniauth-linkedin gem) - ruby-on-rails

I'm using the omniauth-linkedin gem for my rails application:
https://github.com/skorks/omniauth-linkedin
It should be taking into account new LinkedIn permissions request procedures and scopes, but I am not having success obtaining either email addresses or full profiles (anything other than the default profile overviews).
Here is my omniauth.rb file:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :scope => 'r_fullprofile r_emailaddress'
end
The full profile and email address request are going through to LinkedIn initially, before the user enters her/his credentials. However, the scope requests are lost once the user signs in, and only the default profile overview information is accessible.
I think my problem has something to do with having to specifically request those fields within the scopes that I want, as is mentioned on the gem page (https://github.com/skorks/omniauth-linkedin). Still, I have tried adding specific field requests to my omniauth.rb file with no success (email field request below):
Rails.application.config.middleware.use OmniAuth::Builder do
provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], :scope => 'r_fullprofile+r_emailaddress',
:fields => ["id", "email-address", "first-name", "last-name", "headline", "industry", "picture-url", "public-profile-url", "location", "positions", "educations"]
end
Apparently, I am supposed to request the default fields of the profile overview in addition to the non-default fields like email-address, positions, and educations in order to access these latter non-default fields.
LinkedIn email-address should be straightforward, as it is not a structured object like positions or educations are, and I believe I am missing code for specific fields within positions and educations that I want (not sure how i would write that and would love some input on that as well). I am using my new API keys, so I'm not sure what the problem may be. Do I need some kind of special permission from LinkedIn? Help is appreciated! Thank you.
Also, here is the relevant code for my auth controller:
require 'linkedin'
class AuthController < ApplicationController
def auth
client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
request_token = client.request_token(:oauth_callback =>
"http://#{request.host_with_port}/callback")
session[:rtoken] = request_token.token
session[:rsecret] = request_token.secret
redirect_to client.request_token.authorize_url
end
def callback
client = LinkedIn::Client.new(ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'])
if current_user.atoken.nil? && current_user.asecret.nil?
pin = params[:oauth_verifier]
atoken, asecret = client.authorize_from_request(session[:rtoken], session[:rsecret], pin)
current_user.atoken = atoken
current_user.asecret = asecret
current_user.uid = client.profile(:fields => ["id"]).id
flash.now[:success] = 'Signed in with LinkedIn.'
elsif current_user.atoken && current_user.asecret
client.authorize_from_access(current_user.atoken, current_user.asecret)
flash.now[:success] = 'Signed in with LinkedIn.'
end

Not sure if this is the most elegant solution, but this worked for me
I just added the config with the scope passed in the request_token_path
LINKEDIN_CONFIGURATION = { :site => 'https://api.linkedin.com',
:authorize_path => '/uas/oauth/authenticate',
:request_token_path =>'/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress+r_network+r_contactinfo',
:access_token_path => '/uas/oauth/accessToken' }
client = LinkedIn::Client.new(LINKEDIN_API_KEY, LINKEDIN_SECRET_KEY, LINKEDIN_CONFIGURATION )
and the rest of the code is the same.
Be sure to change the client constructor in the callback method as well.

Related

Access github API with rails oauth plugin

I'm implementing an application that is supposed to be able to talk to different APIs on behalf of its users. Amongst others, this includes github. I'm using the oauth-plugin (https://github.com/pelle/oauth-plugin) to perform the authentication for each API. Unfortunately, this doesn't work for Github.
Here's my current GithubToken implementation:
class GithubToken < ConsumerToken
GITHUB_SETTINGS={
:site=>"https://github.com",
:request_token_path => "/login/oauth/request_token",
:authorize_path => "/login/oauth/authorize",
:access_token_path => "/login/oauth/access_token",
}
def self.consumer
#consumer||=create_consumer
end
def self.create_consumer(options={})
OAuth::Consumer.new credentials[:key],credentials[:secret],GITHUB_SETTINGS.merge(options)
end
def self.get_request_token(callback_url, scope=nil)
https://github.com/login/oauth/authorize
consumer.get_request_token({:oauth_callback=>callback_url}, :scope=>scope||credentials[:scope]||"")
end
end
When starting the authentication process, I get a 403 error during the get_request_token call. I assume the request_token_path is somehow wrong, but was unable to find any information on the correct path. Searching google with github as part of the search term was also not very helpful. Will try omniauth now, but as I'm planning on using the provider capabilities of the oauth-plugin, as well, any help would be much appreciated.
Ok, solved it. The following configuration in initialisers/oauth_consumers.rb will do the trick:
OAUTH_CREDENTIALS={
:github=>{
:key => "KEY",
:secret => "SECRET",
:expose => false, # expose client at /oauth_consumers/twitter/client see docs
:oauth_version => 2,
:options => {
:site => 'https://github.com',
:authorize_url => '/login/oauth/authorize',
:token_url => '/login/oauth/access_token'
}
}
}
Also make sure to register /oauth_consumers/github/callback2 as your callback URL.

How do I insert X-PAYPAL headers with Rails Invoice SDK?

I'm using the paypal SDK for invoicing located here:
https://github.com/paypal/invoice-sdk-ruby
This works great.
I integrated the paypal permissions SDK for rails:
https://github.com/paypal/permissions-sdk-ruby
The authorization workflow is working great.
So now I need to put them together. The documentation for the permissions sdk leaves off after you get your token. It doesn't explain how to use it with the other paypal SDKs (at least not so I could understand :D ) The invoice sdk tells you to see the Auth sdk.
Paypal tells me:
# Third-party Auth headers
-H "X-PAYPAL-SECURITY-SUBJECT:<receiverEdress>" # Merchant's PayPal e-mail
-H "X-PAYPAL-AUTHENTICATION:<OAuthSig>" # Generated OAuth Signature
Don't know how to insert that. The request is generated here in my model:
#create_and_send_invoice = api.build_create_and_send_invoice(paypalized || default_api_value)
The data itself is assembled in the invoice model like so:
paypalized = {
:access_token => self.user.paypal_token,
:invoice => {
:merchantEmail => self.user.paypal_email || self.user.email,
:payerEmail => self.client.email,
:itemList => #itemlist,
:currencyCode => "USD",
:paymentTerms => "DueOnReceipt",
:invoiceDate => self.updated_at,
:number => self.name,
:note => self.description,
:merchantInfo => #businessinfo
# project / Invoice title?
} # end invoice
} # end paypalized
return paypalized
This implementation is not working and the access_token field is being rejected. I looked through the gems associated with the sdks but can't see where the headers themselves are built or how to interact with that.
UPDATE: Found this which gives me a clue...
INVOICE_HTTP_HEADER = { "X-PAYPAL-REQUEST-SOURCE" => "invoice-ruby-sdk-#{VERSION}" }
This seems to be used here during calls in the paypal-sdk-invoice gem:
# Service Call: CreateAndSendInvoice
# #param CreateAndSendInvoiceRequest
# #return CreateAndSendInvoiceResponse
def CreateAndSendInvoice(options = {} , http_header = {})
request_object = BuildCreateAndSendInvoice(options)
request_hash = request_object.to_hash
...
I notice that there's two arguments: options and http_header. It's possible I can modify the http_header argument and pass it this way in my controller:
#create_and_send_invoice_response = api.create_and_send_invoice(#create_and_send_invoice, #cutsom_header)
or maybe
#create_and_send_invoice = api.build_create_and_send_invoice(data, custom_header)
I'll keep this updated since I googled around a lot and couldn't find any clear answers on how to do this...
You have to pass the token and token_secret while creating API object for third-party authentication.
#api = PayPal::SDK::Invoice::API.new({
:token => "replace with token",
:token_secret => "replace with token-secret" })

How to fetch fields that require access token using fbgraph

I am trying to fields that require access token, fields like age_range, here are the list of fields
https://developers.facebook.com/docs/reference/api/user/
user = FbGraph::User.new('me', :access_token => access_token).fetch
I am trying
user.age_range #=> nil
Where as when i am trying in facebook graph api explorer using http://developers.facebook.com/tools/explorer
facebook_id?fields=age_range
It shows the Json data for the same user.
Did it using omniauth ,Added info_fields with scope
provider :facebook, facebook_app_id, facebook_secret_key, { :info_fields => 'age_range', :scope => 'email,offline_access' }

Rails, OmniAuth, google_oauth2, google-api-client, Moments.insert... 401 unauthorized... why?

I haven't been able to find an answer to this online -- aside from using the Google+ Sign In button, which I don't want to use at this point because I don't want to get into Javascript if I don't have to.
I have a Ruby on Rails application (ruby v1.9.3, rails v3.2.13) in which I've hooked up OmniAuth and I'm using the google_oauth2 gem to integrate with Google+.
My simple goal is to allow a user to authenticate with Google+, grant access to my Google API project, and then be able to post a moment to the Google+ user's vault using the google-api-client gem.
I have already setup my Google API Project, created the OAuth 2.0 for Web Applications, and enabled Google+ API service.
I have OmniAuth setup with the following provider and I've added the request_visible_actions option to allow me to post (I think this is correct but haven't seen this used from any code examples I've looked at online...):
provider :google_oauth2, CLIENT_ID, CLIENT_SECRET, {
access_type: 'offline',
scope: 'userinfo.email,userinfo.profile,plus.me,https://www.googleapis.com/auth/plus.login',
request_visible_actions: 'http://schemas.google.com/AddActivity',
redirect_uri: 'http://localhost/auth/google_oauth2/callback'
}
When I redirect my user to /auth/google_oauth2, it sends the user to Google+ to authorize my app and when the user approves, it returns to my callback where I can access the request.env["omniauth.auth"] and it has all the information I would expect, including tokens, email address, etc. I'm storing the access_token from auth["credentials"]["token"].
So far so good, right?
When I try to post the moment using the following code, I encounter an exception indicating a 401 unauthorized error.
client = Google::APIClient.new
client.authorization.access_token = self.access_token
plus = client.discovered_api('plus', 'v1')
moment = {
:type => 'http://schemas.google.com/AddActivity',
:target => { :id => Time.now.to_i.to_s,
:description => message,
:name => message
}
}
# post a moment/activity to the vault/profile
req_opts = { :api_method => plus.moments.insert,
:parameters => { :collection => 'vault', :userId => 'me', },
:body_object => moment
}
response = client.execute!(req_opts).body
I have also tried replacing
client.authorization.access_token = self.access_token
with
credentials = Hash.new
credentials[:access_token] = self.access_token
credentials[:refresh_token] = self.refresh_token
credentials[:expires_at] = self.expires_at
client.authorization.update_token!(credentials)
But no luck.
I think the issue either has to do with:
OmniAuth not issuing the request_visible_actions to Google correctly
Me not setting the token in the Google::APIClient object properly
I've gotten this far using the following resources, but I'm officially stuck:
http://blog.baugues.com/google-calendar-api-oauth2-and-ruby-on-rails
https://developers.google.com/+/api/latest/moments/insert
Any ideas would be appreciated!
Here is my working code from web app using 'omniauth-google-oauth2' along with 'google-api-client'. This sample code uses calendar API, but I guess it will work for you.
require 'google/api_client'
class Calendar
def initialize(user)
#user = user
end
def events
result = api_client.execute(:api_method => calendar.events.list,
:parameters => {'calendarId' => 'primary'},
:authorization => user_credentials)
result.data
end
private
def api_client
#client ||= begin
client = Google::APIClient.new(application_name: 'xxx', application_version: '0.0.1')
client.authorization.client_id = ENV["GOOGLE_KEY"]
client.authorization.client_secret = ENV["GOOGLE_SECRET"]
client.authorization.scope = 'https://www.googleapis.com/auth/calendar'
client
end
end
def calendar
#calendar ||= api_client.discovered_api('calendar', 'v3')
end
def user_credentials
auth = api_client.authorization.dup
# #user.credentials is an OmniAuth::AuthHash cerated from request.env['omniauth.auth']['credentials']
auth.update_token!(access_token: #user.credentials.token)
auth
end
end
In the API console, did you register as a Web application or installed application?
I think for your case you must choose the installed application, so that the token is valid if user is not online.
Try changing https://www.googleapis.com/auth/plus.login with just plus.login. Its working for me with the same setup.

"Access to posting shares denied" error when posting public messages using the linkedin api

I am trying send out messages using the linkedin ruby api to the API end point : http://api.linkedin.com/v1/people/~/shares, but everytime I get this error : LinkedIn::Errors::AccessDeniedError ((403): Access to posting shares denied). What is wrong?
code:
#fetch client object
client = LinkedIn::Client.new('er0xev11ktyj', 'qw7hfgR4wT8Hztpl')
#auth
request_token = client.request_token(:oauth_callback => callback_url)
session[:linkedin_token] = request_token.token
session[:linkedin_secret] = request_token.secret
redirect_to request_token.authorize_url
#inside callback url
atoken,asecret = client.authorize_from_request(session[:linkedin_token], session[:linkedin_secret], params[:oauth_verifier])
#api call for posting message
client.authorize_from_access(atoken, asecret)
client.add_share({:comment => "Hey!"}) #throws error!
Do I need to specify scope parameters? If yes, how do I implement this in my code?
Thanks
Override the default consumer options and append scope to the request_token_path
consumer_options = {
:request_token_path => "/uas/oauth/requestToken?scope=r_basicprofile+w_share",
:access_token_path => "/uas/oauth/accessToken",
:authorize_path => "/uas/oauth/authorize",
:api_host => "https://api.linkedin.com",
:auth_host => "https://www.linkedin.com"
}
LinkedIn::Client.new(ckey, csecret, consumer_options)

Resources