Attempting a PUT to Google Groups API using OAuth2 gem and Ruby - ruby

I'm trying to do a PUT call on a Google Groups API using Ruby and the OAuth2 GEM. I've managed to authenticate OK, and the GET call works properly, but I can't seem to get the call to use the PUT method. I thought the following would work, since OAuth2 uses Faraday, but I just keep getting the 400 message back, with an indication that something's "required":
data = access_token.put('https://www.googleapis.com/groups/v1/groups/{email address}?alt=json').parsed do |request|
request.params['email'] = "{email address}"
end
Has anyone got a working example of passing parameters to a PUT request?

OK. Looks like the ".parsed" was interfering with the call here's what works, with some additions to the request object:
response = access_token.put('https://www.googleapis.com/groups/v1/groups/{email address}') do |request|
request.headers['Content-Type'] = 'application/json'
request.body='{"email": "{email address}"}'
end
# check this
puts response.status
# works if it's 200

Related

Ruby POST call from server fails

I'm trying to make a spotify web manager with ruby, to make that I'm following the Authorization Guide.
My backend looks similar to the example made by the spotify's guys in this github. You can see mine here code here.
So the error I'm getting are 400 - Bad request or 415 - Unsupported media type.
At first I was using the net/http core library, but because maybe I was doing something wrong I've used Typhoeus and the result are the same.
This is the code is not working:
request = Typhoeus::Request.new("https://accounts.spotify.com/api/token",
method: :post,
body: {
grant_type: "authorization_code",
code: code,
redirect_uri: "http://localhost:5000/auth/spotify/callback"
},
headers: {
"Authorization": "Basic #{Base64.strict_encode64("#{settings.spotify_id}:#{settings.spotify_key}")}"
},
followlocation: true
)
logger.info request.inspect
request.on_complete do |response|
logger.info "[]" * 100
logger.info response
if response.success?
logger.info "SUCCESS"
elsif response.timed_out?
logger.info "TIMED OUT"
elsif response.code == 0
logger.info response.return_message
else
logger.info "HTTP request failed: #{response.code.to_s}"
redirect '/auth/failure'
end
end
request.run
Well, if someone of you have any idea of what is happenning, It would be helpful to know it.
Thanks in advance.
Edit
The string interpolation is is working properly, has been tested on console.
"Basic #{Base64.strict_encode64("#{settings.spotify_id}:#{settings.spotify_key}")}"
About the redirect_uri, must to work well, one thing because the guide is explained with localhost example, and second, the first request explained on the Authorization Guide is working properly, the problem happens when I'm trying to do the 4 step on that guide.
Are you sure that kind of string interpolation works? Did you look at the traffic in wireshark to see if it is working correctly? It looks suspicious cause you use double-quotes within double quotes and still expect it to work. If you don't wanna set up wireshark, have your app post the request text on the console. Furthermore, are you sure Spotify will allow redirect_uri's with localhost? Also, when do you get the 400, and when do you get the 415? This is important information, you can't just conflate them like that.
I've changed the Typhoeus gem for HTTParty, and now the error is becoming clearer.
The main thing here is not the 400 or the 415 error, is the message attached to this error. The error here is:
"error"=>"invalid_grant", "error_description"=>"Invalid authorization code"
So, It's my fault not to be aware of that, but was not clear the message, sometimes the fatigue and frustration makes you not seeing the obvious.
Now, just have to know why the auth. code is not valid.
Anyway thanks for the help.

Requesting An Access Token from Google API Returns 302

I'm trying to get an access token from Google API in my Ruby on Rails app, as part of an overall goal of setting up a raketask. I am able to get an Auth Code fine, but when I make a post request to get an access token, I am getting a 302 error. I'll describe my current code first, and afterward list how I've tried to solve the problem so far.
Current code:
#users_controller
def auth_access
client = Signet::OAuth2::Client.new(
:authorization_uri => 'https://accounts.google.com/o/oauth2/auth',
:token_endpoint_uri => 'https://accounts.google.com/o/oauth2/token',
:client_id => ENV['OAUTH_CLIENT_ID'],
:client_secret => ENV['OAUTH_CLIENT_SECRET'],
:scope => 'https://www.googleapis.com/auth/analytics.readonly',
:redirect_uri => 'http://localhost:3000/google/auth_callback'
)
redirect_to client.authorization_uri.to_s
end
This part works fine so far. It redirects to the consent page, and when the user agrees it then redirects them to the page with the auth code in the url parameters. Next I take that auth code and try to make a POST request to API for an access token:
#users_controller
def auth_callback
http = Net::HTTP.new('accounts.google.com')
path = '/o/oauth2/token'
data = "code=#{params['code']}&client_id=#{ENV['OAUTH_CLIENT_ID']}&client_secret=#{ENV['OAUTH_CLIENT_SECRET']}&redirect_uri=http://localhost:3000/auth_final&grant_type=authorization_code"
response = http.post(path, data)
end
This when I run into a problem. The Google API returns a 302, and includes a message saying something akin to "we moved to 'https://accounts.google.com/o/oauth2/token'".
Here's how I've tried to fix the problem so far:
I assumed that the problem was that the http.post method is making a call to an http and not https.
I've tried including
http.use_ssl = true
http.ssl_version = :SSLv3
This returns the error "SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: wrong version number".
I can take a guess at what this means, but I am still unsure of what the actual problem is and how to solve it. Googling the error message has not been a help.
In a similar vein, I tried using gems to make the https call for me, in particular HTTParty and Typheous, although I was not able to make any progress with them (and am still not even sure that it's an http/https problem).
I've tried using the Signet-Rails gem. This was the most productive method by far, making a successful API call and returning the information. However, it either wasn't saving the refresh token or I cannot find where it is being saved. As I need access to that token to run the rake tasks, I gave up on Signet-Rails.
I tried using Legato, and was constantly running into various problems. Overall, Legato left me with the impression that it did not integrate getting the auth code, consent and tokens into the app, instead requiring the developer to set those up in advance outside of the app's scope. I want to be able to set up the auth code as part of the app. If I am understanding Legato properly, then it is not the gem I need.
I've also tried other various odds and ends but to no avail. The above solutions were the tactics I kept coming back to. Primarily I'm looking for an answer to what is going wrong in my code, and what is the best avenue to fix it (and if I was going down the right track with any of my attempted solutions above, which one?)
Thanks for taking the time to read this and answer!
(on a complete sidenote, those last three list items should be 2, 3, 4, but the stackoverflow text editor thinks it knows better than me...)
Specify the port:
http = Net::HTTP.new('accounts.google.com', 443)
Source: SSL Error on HTTP POST (Unknown Protocol)

Why does Google's Custom Search API say that I'm missing an access token when using the Ruby client?

I'm trying to use Google's Custom Search API through the Google API Ruby client. I have setup my API key through the Google API console, and have also created my CSE. Based on the documentation, it seems that, as long as I provide an API key (which I am doing), I shouldn't need an OAuth2 authentication token to call the list method. However, when I try to execute the code below, I get the following error:
ArgumentError: Missing access token.
What am I missing? Here's my code:
# create client
client = Google::APIClient.new
# Fetch discovery doc
search = client.discovered_api('custom search')
# Call list method
response = client.execute(
search.cse.list, 'key' => '<my API key>', 'cx' => '<my CSE id>', 'alt' => 'json', 'q' => 'hello world'
)
I believe this is in fact a bug in the client (it's in alpha). After fiddling with it a little more, I've found a workaround:
just after creating the client object, assign it a "dummy" access token:
client.authorization.access_token = '123'
then you can call the search.cse.list method without getting the 'ArgumentError: Missing access token.' error.
If you're just after using Google CSE with ruby, try google-cse. I just built the gem, although I've been using it for a while privately. Much easier to work with than the alpha client
I found out that adding client.retries = 3 to my code solves this problem.
With the current version of the gem (0.7.1), you need to set the authorization to nil in addition to setting the key:
require 'google/api_client'
client = Google::APIClient.new
client.key = ENV['GOOGLE_API_KEY']
client.authorization = nil
client.execute ...

401 error with Ruby OAuth for Twitter

xI've been working for days to get Twitter to authenticate with Ruby, but I'm not having any luck.
My first attempt was something like this:
class TwitterController < ApplicationController
def index
#callback_url = "http://dev.twipler.com:3000/twitter/auth"
#auth= TwitterOAuth::Client.new( :consumer_key => "xxx", :consumer_secret => "xxxxxxxxxxxxxxxxx" )
#rtoken = #auth.request_token :oauth_callback => #callback_url
#token = #rtoken.token
#secret = #rtoken.secret
#link = #rtoken.authorize_url
session['token' ] = #token
session['secret'] = #secret
redirect_to #link
end
def auth
#auth.authorize_from_request(session[:rtoken], session[:rsecret], params[:oauth_verifier])
end
end
And a very similar way but with the Twitter gem, and the same with the OAuth gem directly. No matter what OAuth::Consumer::token_request dies with a 401 error.
So, out of desperation I attempted to git clone Snitter, add my Twitter creds, and try it, but it too dies with a 401.
I've tried using localhost:300/twitter/auth, http://dev.twipler.com:3000/twitter/auth, and a bit.ly for each of the former 2. Nothing works.
Any help?
EDIT: Of course I would forget to do the most logical thing to do and delete my secrets. (They've been changed ;)).
You may want to edit your consumer secret out. With that, anyone can make requests on behalf of your app.
That said, make sure your system time is synced to an ntp server. If your system time has drifted fast or slow, OAuth requests will fail, since their include a timestamp and relatively short TTL. I had this exact problem a while back.
Failing that, you can crack open the oauth gem and turn on HTTP debugging, which will show you the full HTTP transaction including any error message returned.

how can I capture response from twitter.com? ( ruby + twitter gem)

how can I capture response from twitter.com? To make sure that everything went ok?
I am using ruby and ruby twitter gem and the my code is basically like that
oauth = Twitter::OAuth.new('consumer token', 'consumer secret')
oauth.authorize_from_access('access token', 'access secret')
client = Twitter::Base.new(oauth)
client.update('Heeeyyyyoooo from Twitter Gem!')
The update twitter api method will send back a response that will let you know if everything went okay. It can respond in either json or xml, I'm sure the twitter gem is using one or the other as a default. You need to save the return value to a variable and parse it, if you have a status id in there then it worked. Try using a token or secret to check what happens when it errors. I would suggest changing your last line to this
ret = client.update('Heeeyyyyoooo from Twitter Gem!')
and then add this line below that to check out what you got back
puts ret.inspect
or
logger.info ret.inspect
or your choice of logging method
[Edit]
It looked like the twitter gem hides the twitter api's actual response from you, parses it for you and just returns you the relevant bits. in the case of the update method it just returns you the id of your new tweet. you can view the id like this
puts ret.id
If you use another library to connect to the twitter api and need to parse xml or json responses then then the rest of this answer may be what you are looking for.
[/Edit]
If you are not using a gem that parses twitter api responses for you then you will need to use something to parse the twitter api's responses into data that you can do something with. There are tons of ways to do this depending on what format you want to parse (json or xml)
My preferences:
XML : Hpricot : gem install hpricot : http://github.com/hpricot/hpricot
json : json : gem install json : http://github.com/flori/json
Here is more information on what the twitter api update method returns: http://apiwiki.twitter.com/Twitter-REST-API-Method:-statuses%C2%A0update
This worked for me...
begin
resp = Twitter.update(params[:message])
rescue Exception => e
# e.message contains the twitter response
end

Resources