Withings API: The callback URL is either unknown or invalid - ruby-on-rails

I'm trying to set a notification in the withings API (with the withings-simplificator gem). I always get this error, no matter what URL I enter or if I encode it or not:
irb(main):013:0> user.subscribe_notification('http://foo.bar.com', 'test subscription')
Withings::ApiError: The callback URL 'http://foo.bar.com' is either unknown or invalid - Status code: 293
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:80:in `verify_response!'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:22:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:27:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/user.rb:26:in `subscribe_notification'
from (irb):13
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:110:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:9:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:68:in `console'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:8:in `require'
from bin/rails:8:in `<main>'
Has anyone encountered this and has a solution?
Update 1:
So I tried without the withings simplificator gem:
API_KEY = '123'
API_SECRET = '456'
USER_ID = '789'
USER_KEY = 'abc'
USER_SECRET = 'def'
CONFIGURATION = { site: 'https://oauth.withings.com',
request_token_path: '/account/request_token',
access_token_path: '/account/access_token',
authorize_path: '/account/authorize',
http_method: :get,
scheme: :query_string
}
#consumer = OAuth::Consumer.new API_KEY, API_SECRET, CONFIGURATION
#access_token = OAuth::AccessToken.new #consumer, USER_KEY, USER_SECRET
url = ERB::Util.url_encode("www.foo.bar/trigger")
comment = ERB::Util.url_encode("Trigger")
response = #access_token.get("https://wbsapi.withings.net/notify?action=subscribe&userid=#{USER_ID}&callbackurl=#{url}&comment=#{comment}")
JSON.parse(response.body)
And same error:
irb(main):051:0> JSON.parse(response.body)
=> {"status"=>293}
What am I doing wrong?

You have to make sure during setup
your "trigger url" exists
it responds with "ok" to a POST
it is fast ... I couldn't figure this out exactly how fast, but I think the response time should be < 1 second
With an environment like this, my code above works.

Your notification endpoint going to do two operations:
it is going to respond test request response (while you register it will check your URL is exist or not). You will receive call with empty body object. If it is not have userid, it is not a data notification, so you have to respond status as 200 with empty body;
after successful registration you will receive data alert. This time you can handle by your business logic.

Related

Failed to open TCP connection to oauth.intuit.com:443 (getaddrinfo: Name or service not known)

I'm trying to integrate my Ruby on Rails app to Quickbooks Online. I'm following the steps of this video. And I am stuck when I try to authenticate by pressing the "Connect to QuickBooks" button.
I get this error;
This is the Full Trace;
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:960:in `initialize'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:960:in `open'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:960:in `block in connect'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/timeout.rb:95:in `block in timeout'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/timeout.rb:105:in `timeout'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:958:in `connect'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:943:in `do_start'
/home/kvothe/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/net/http.rb:932:in `start'
My Initializer (quickbooks.rb);
QB_KEY = "MY_CLIENT_KEY"
QB_SECRET = "MY_CLIENT_SECRET"
$qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, {
:site => "https://oauth.intuit.com",
:request_token_path => "/oauth/v1/get_request_token",
:authorize_url => "https://appcenter.intuit.com/Connect/Begin",
:access_token_path => "/oauth/v1/get_access_token"
})
Quickbooks.sandbox_mode = true
My Controller (vendors_controller.rb);
def authenticate
callback = oauth_callback_vendors_url
token = $qb_oauth_consumer.get_request_token(:oauth_callback => callback)
session[:qb_request_token] = Marshal.dump(token)
redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return
end
def oauth_callback
at = Marshal.load(session[:qb_request_token]).get_access_token(:oauth_verifier => params[:oauth_verifier])
session[:token] = at.token
session[:secret] = at.secret
session[:realm_id] = params['realmId']
redirect_to root_url, notice: "Your QuickBooks account has been successfully linked."
end
I was getting an Undefined Method: URI.escape() error but then I switched to Ruby 2.7.2
Currently using Ruby 2.7.2 and Rails 6.1.4
I think the error caused by the URL address (located in the initializer) I use to get authentication from intuit. I am using exactly the same URL's showed in the tutorial but I'm afraid it may be to old and not work anymore. But I don't know what to replace it with. And also how do I integrate my app with OAuth2.0? I can't find any recent tutorials best I got is this 7 year old tutorial by "Minimulcasts".
PS: Also when trying diffeent URL addresses I got Net::HTTPRetriableError in VendorsController#authenticate 302 "Moved Temporarily" error as well.
Intuit Developer no longer supports OAuth 1.
You will need to follow the documentation on the https://developer.intuit.com platform.
Unfortunately these docs are very outdated & support on the Help Forums is very poorly automated.

Fetching Google Analytics profiles using Garb

I use Garb(0.9.8) to fetch data from Google Analytics from our server directly using OAuth1. As Google only supports OAuth2 now so I switched to Signet gem and used a service account to get a access_token from the server directly as we need only server to server interaction.
key = Google::APIClient::KeyUtils.load_from_pkcs12(p12_key_path, 'notasecret')
client = Google::APIClient.new(application_name: 'Service account demo', application_version: '0.0.1')
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => ['https://www.googleapis.com/auth/analytics', 'https://www.googleapis.com/auth/analytics.readonly'],
:issuer => <service account email>,
:signing_key => key
)
access_token = client.authorization.fetch_access_token!["access_token"]
The token is valid and i double checked it from the Google API playground.
The service account has been added as a user with all permissions to my Google Analytics account.
If feasible I wanted to use Garb instead of completely switching to google-api-client gem so as to avoid re-writing a lot of exisiting code.
Then to make Garb use the access_token obtained and fetch all profiles I did the following
garbsession = Garb::Session.new
garbsession.access_token = access_token
Garb::Management::Profile.all(garbsession)
But I am getting an error:
NoMethodError: undefined method `get' for #<String:0xd877aa0>
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/request/data.rb:94:in `oauth_user_request'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/request/data.rb:41:in `send_request'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/management/feed.rb:21:in `response'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/management/feed.rb:13:in `parsed_response'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/management/feed.rb:17:in `entries'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/garb-0.9.8/lib/garb/management/profile.rb:14:in `all'
from (irb):47
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/railties-3.2.19/lib/rails/commands/console.rb:47:in `start'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/railties-3.2.19/lib/rails/commands/console.rb:8:in `start'
from /home/alok/.rvm/gems/ruby-1.9.3-p385/gems/railties-3.2.19/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Am I doing something wrong? Can I use an Access token obtained by some other method in Garb and then access the Google Analytics API ?
The mistake I made is Garb::Session.access_token should be an instance of OAuth2 client and not the access token itself. I am posting the working code in my answer so that it might help other later !. Came across the code when browsing the Legato gem for a solution to the problem. Github issue link from where I found the solution- https://github.com/tpitale/legato/issues/90
p12_key_path = File.join(Rails.root, "config", <p12_key_path>)
key = Google::APIClient::KeyUtils.load_from_pkcs12(p12_key_path, 'notasecret')
auth_client = Signet::OAuth2::Client.new(
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
audience: 'https://accounts.google.com/o/oauth2/token',
scope: 'https://www.googleapis.com/auth/analytics.readonly',
issuer: <ga_service_account email>,
signing_key: key
)
access_token = auth_client.fetch_access_token!
raise "Google OAuth Access Token is blank" if access_token["access_token"].blank?
oauth_client = OAuth2::Client.new("", "", {
authorize_url: 'https://accounts.google.com/o/oauth2/auth',
token_url: 'https://accounts.google.com/o/oauth2/token'
})
token = OAuth2::AccessToken.new(oauth_client, access_token["access_token"], expires_in: 1.hour)
Garb::Session.access_token = token
profile = Garb::Management::Profile.all

GET method with json body

I have to consume methods from an external API provided, and one method is a GET with a json body. I'm making the connection through rails using rest-client gem that makes that job.
I know that RestClient.post accepts json:
RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json
And also for my case works perfectly. But if i change the .post to .get, i get this error:
ArgumentError: wrong number of arguments (3 for 2)
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/rest-client-1.6.7/lib/restclient.rb:67:in `get'
from /Users/toptierlabs/Desktop/Proyectos/AppraisalLane/app/models/autoniq.rb:8:in `getCircleInventory'
from (irb):3
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Is there any way in Rails to do a GET with a json body? Or any possible solution to translate a "get with a json body" to something else? Is not necessary to use the rest-client gem, if any one have another solution is welcome too.
Thanks!
Solved:
RestClient.get "http://example.com/resource", params: {'json' => { 'x' => 1 }.to_json},:content_type => :json, :accept => :json

OAuth::Unauthorized: 401 using dropbox-api gem in Rails 3.2 console

I am trying to authorize using dropbox-api gem just in the Rails console
Here's how I fired it up in the console:
But I keep on getting 401 Unauthorized error upon accessing via oauth_verifier
Here's the gem that I am using: https://github.com/futuresimple/dropbox-api
> Dropbox::API::Config.app_key = MY_APP_TOKEN
> Dropbox::API::Config.app_secret = MY_APP_SECRET
> consumer = Dropbox::API::OAuth.consumer(:authorize)
> request_token = consumer.get_request_token
> request_token.authorize_url(:oauth_callback => 'http://localhost:3000/callback/dropbox')
> hash = { oauth_token: request_token.token, oauth_token_secret: request_token.secret}
> request_token = OAuth::RequestToken.from_hash(consumer, hash)
> result = request_token.get_access_token(:oauth_verifier => request_token.token)
ERROR:
1.9.3-p448 :019 > access_token = request_token.get_access_token(:oauth_verifier => request_token.token)
OAuth::Unauthorized: 401 Unauthorized
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/oauth-0.4.7/lib/oauth/consumer.rb:216:in `token_request'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/oauth-0.4.7/lib/oauth/tokens/request_token.rb:18:in `get_access_token'
from (irb):19
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Any workarounds will be appreciated.
Moving my comment to an answer:
Be sure to actually visit the authorize URL and "allow" the app before trying to call get_access_token.

Multipule posts in loop with FbGraph gives: OAuthException :: (#1) An error occured while creating the share

I'm having an issue posting posts to a page, and only get the helpful error:
OAuthException :: (#1) An error occured while creating the share
The first 20 or so posts worked great, then it started to error.
Does facebook have a limit on the number of posts one can make to a page (spam) or something?
I can reproduce form rails c and I have triple checked my access_token and can manually post from FB directly.
(I'm using the page access_token not my user one)
I opened a issue on FbGraph's githup but nov seems to think its a FB issue.
My Code:
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 1
end
Backtrace:
FbGraph::InvalidRequest: OAuthException :: (#1) An error occured while creating the share
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:47:in `block in handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `each'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:142:in `handle_response'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:55:in `post'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/connections/feed.rb:14:in `feed!'
from (irb):9:in `block in irb_binding'
from (irb):5:in `each'
from (irb):5
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:47:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Update:
It looks like my access_token was banned for 24 hours.
I was just able to add another 28 posts to the page before getting this error again. I tried with a 10sec sleep this time but still got banned... I guess I will try with a 60sec sleep tomorrow.. :(
I was not able to fix this problem but I have worked around it.
By uploading 1 post every 3 minutes I was able to get 200-300 posts up a day.
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 180
end
I hope this helps someone else with this problem.

Resources