I intend to send GET request with net/http just like that:
require 'net/http'
response = Net::HTTP.get_response("example.com", "/whoareyou.json")
but I need to include key and secret in the url. I tried to make it like this:
require 'net/http'
response = Net::HTTP.get_response("<key>:<secret>#example.com", "/whoareyou.json")
But unfortunately I'm getting nasty error:
/usr/lib/ruby/1.9.1/net/http.rb:762:in `initialize': getaddrinfo: Name or service not known (SocketError)
Net::HTTP does not support basic authentification from the URL. You need to call req.basic_auth 'user', 'pass'
http://ruby-doc.org/stdlib-2.1.3/libdoc/net/http/rdoc/Net/HTTP.html#class-Net::HTTP-label-Basic+Authentication
I suggest also tu use the HTTP Party gem ( https://github.com/jnunemaker/httparty ) that really simplify most of the HTTP stuff , see this answer for instance to see how basic auth can be used with HTTP party : How to use basic authentication with httparty in a Rails app?
In your example:
res = HTTParty.get("http:example.com/whoareyou.json", :basic_auth=> {:username =>user, :password => password})
:basic_auth => auth)
Related
Now I took a sample code of Twitter v2 API from this link. This sample code shows how OAuth and twitter v2 API work for positng a tweet. It works fine with my consumer key and consumer secret.
And I want to simplify the code like below. It assumes that the access token and access token secret are already known and it skips the process of user's approval, like providing the URL that provides PIN.
require 'typhoeus'
require 'json'
consumer_key = CONSUMER_KEY
consumer_secret = CONSUMER_SECRET
token = ACCESS_TOKEN
token_secret = ACCESS_TOKEN_SECRET
consumer = OAuth::Consumer.new(consumer_key, consumer_secret, :site => 'https://api.twitter.com')
options = {
:method => :post,
headers: {
"User-Agent": "v2CreateTweetRuby",
"content-type": "application/json"
},
body: JSON.dump("Hello, world!")
}
create_tweet_url = "https://api.twitter.com/2/tweets"
request = Typhoeus::Request.new(create_tweet_url, options)
access_token = OAuth::Token.new(token, token_secret)
oauth_params = {:consumer => consumer, :token => access_token}
oauth_helper = OAuth::Client::Helper.new(request, oauth_params.merge(:request_uri => create_tweet_url))
request.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
response = request.run
puts response
Then, I see the below error message.
ruby test_tweet.rb
/usr/local/lib/ruby/gems/3.1.0/gems/oauth-0.5.10/lib/oauth/request_proxy.rb:18:in `proxy': Typhoeus::Request (OAuth::RequestProxy::UnknownRequestType)
from /usr/local/lib/ruby/gems/3.1.0/gems/oauth-0.5.10/lib/oauth/signature.rb:12:in `build'
from /usr/local/lib/ruby/gems/3.1.0/gems/oauth-0.5.10/lib/oauth/signature.rb:23:in `sign'
from /usr/local/lib/ruby/gems/3.1.0/gems/oauth-0.5.10/lib/oauth/client/helper.rb:49:in `signature'
from /usr/local/lib/ruby/gems/3.1.0/gems/oauth-0.5.10/lib/oauth/client/helper.rb:82:in `header'
from test_tweet.rb:28:in `<main>'
When I used irb and tried step by step, this error happens at oauth_helper.header. As this is the first time to use OAuth API, I may be making some easy mistakes. Does anybody find anything wrong in my code?
I confirmed that my access token and access token secret work at https://web.postman.co/.
Thanks.
You need to insert
require 'oauth/request_proxy/typhoeus_request'
and your code may complete task you desire.
Other lines looks good to me!
In oauth/request_proxy.rb, oauth library check class of request object.
https://github.com/oauth-xx/oauth-ruby/blob/master/lib/oauth/request_proxy.rb
return request if request.is_a?(OAuth::RequestProxy::Base)
klass = available_proxies[request.class]
# Search for possible superclass matches.
if klass.nil?
request_parent = available_proxies.keys.find { |rc| request.is_a?(rc) }
klass = available_proxies[request_parent]
end
raise UnknownRequestType, request.class.to_s unless klass
By requiring 'oauth/request_proxy/typhoeus_request', Typhoeus::Request inherits OAuth::RequestProxy::Base and raising UnknownRequestType error can be avoided.
https://github.com/oauth-xx/oauth-ruby/blob/master/lib/oauth/request_proxy/typhoeus_request.rb
I have this very simple Ruby code which makes Ruby POST request.
For some reason it creates 2 requests - one authentication error and one successful request:
def execute
request = HTTPClient.new()
request.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
request.set_auth('https://test.net/api', 'user', 'pass')
request_body = File.read("requests/xml/req.xml")
response = request.post('https://test.net/api', request_body, {'Content-Type' => 'application/xml', 'cache-control' => 'no-cache'}).body
puts 'called'
end
I suppose that some configuration if missing for HTTPClient?
Can you advise how I can fix this?
This is an expected behavior. The client won't send the credentials unless they are required. When the client gets a 401 status code then it sends the request again but now with the credentials.
You can force some clients to send the credentials on the first request.
Ruby's HTTPClient has a force_basic_auth that does that.
I have a mobile app that is signin in with google and sending a server auth code to my backend app.
I want to use this code, along with the client secrets from the google developer console, to retrieve a refresh code for retrieving data from google drive when the user is offline.
Google provides an client for auth calls in ruby, but it seems not to be maintained lately and I could not see a way to do this kind of authorisation in the docs.
In the documentation, I could find an example of how to do this on python:
from oauth2client import client
# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
CLIENT_SECRET_FILE,
['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
auth_code)
I would like to do this in ruby through a post to their https://www.googleapis.com/oauth2/v4/token endpoint. Here is what I've tried so far:
require 'uri'
require 'net/http'
require 'json'
url = URI("https://www.googleapis.com/oauth2/v4/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
headers = {'Content-Type': 'application/json'}
request = Net::HTTP::Post.new(url.request_uri, headers)
request.body = {
code: "#{server_auth_code_sent_to_api}",
client_id: "#{client_id_from_developer_console}",
client_secret: "#{client_secret_from_developer_console}",
grant_type: 'authorization_code',
redirect_url: '',
}.to_json
response = http.request(request)
puts JSON.parse(response.read_body)
But I keep getting the following error:
{
"error": "unsupported_grant_type",
"error_description": "Invalid grant_type: "
}
Does anybody has an idea on what I'm doing wrong, or has a working example on how to do this kind of authorisation?
Thanks in advance.
In case somebody stumbles here with a similar problem, what caused the request to fail was the Content-Type, and not the grant_type parameter.
Digging around in the code for the client library I saw that they use application/x-www-form-urlencoded the endpoint expects a application/x-www-form-urlencoded content type. I adjusted my code accordingly and was able to get a successful response with the valid credentials and token.
Here follows the resulting code:
require 'uri'
require 'net/http'
require 'json'
url = URI("https://www.googleapis.com/oauth2/v4/token")
params = {
"code" => "#{server_auth_code_sent_to_api}",
"client_id" => "#{client_id_from_developer_console}",
"client_secret" => "#{client_secret_from_developer_console}",
"grant_type" => "authorization_code",
"redirect_url" => "#{redirect_url_from_developer_console}",
}
response = Net::HTTP.post_form(url, params)
puts JSON.parse(response.read_body)
I'm using Ruby starting from the "hello world" example. Hello world works find. I'm trying to get this GET to work:
GET /projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now
It works exactly as expected in the Asana API explorer.
I'm using the same URI in my code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
It still returns ID and Name correctly, but it's not what I want.
I can't see why it works in the explorer but not in the GET request. I am using the personal token and the explorer uses OAuth.
My personal token is set correctly before this code. I can create tasks, get projects, get tasks. I just can't more fields in this query like the API explorer.
Added Code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
# set up the request
header = {
"Content-Type" => "application/json"
}
req = Net::HTTP::Get.new(uri.path, header)
req.basic_auth(personal_access_token, '')
res = http.start { |http| http.request(req) }
body = JSON.parse(res.body)
puts "projects: #{body['data']}"
There isn't quite enough code here to know what's wrong. It sounds like your code is working to some degree, but maybe there's something different between using a personal token as opposed to OAuth. According to the Asana API documentation:
Personal Access Tokens should be used similarly to OAuth access tokens when accessing the API, passing them in the Authorization header:
curl -H "Authorization: Bearer ACCESS_TOKEN" https://app.asana.com/api/1.0/users/me
So in addition to the URL, you need to use the correct headers. I'm not sure what HTTP library you use, but here's how I would do it with HTTParty:
require 'uri'
require 'httparty'
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
task = HTTParty.get(uri,
:headers =>
{'Authorization' => "Bearer ${ENV[ACCESS_TOKEN]}"}
).parsed_response
If you put your personal access token in the ACCESS_TOKEN environment variable, that should correctly authenticate you for the request.
Still, it seems like there's something else missing if you can get all the fields. Maybe your personal access token is associated with a different account than your OAuth access token? It might help to check the results of /users/me/ route?
I'm trying to send a request via Typhoeus to Bitbucket's API using Ruby, and I'm doing so with credentials from the "OAuth consumers" page - the consumer_key and consumer_secret. I can get the token just fine, but I get an error when trying to generate the header from the OAuth helper. Here's the relevant code (note that this is not Rails; I'm using Sinatra):
# oauth_token and oauth_token_secret are from a request to https://bitbucket.org/api/1.0/oauth/request_token
#consumer = OAuth::Consumer.new(
consumer_key,
consumer_secret,
)
#token = OAuth::Token.new(oauth_token, oauth_token_secret)
options = {
method: :post,
body: body.to_json
}
oauth_params = {:consumer => #consumer, :token => #token}
hydra = Typhoeus::Hydra.new
url = "https://api.bitbucket.org/2.0/repositories/..."
req = Typhoeus::Request.new(url, options)
oauth_helper = OAuth::Client::Helper.new(req, oauth_params.merge(:request_uri => url))
req.options[:headers].merge!({"Authorization" => oauth_helper.header})
The last line fails with a OAuth::RequestProxy::UnknownRequestType error. Basically what it's saying is that the OAuth RequestProxy doesn't understand the Typhoeus::Request object; from what I can see, it only has support for Net::HTTPGenericRequest and Hash. The Typhoeus documentation indicates that this should work, so it's possible I'm doing something wrong.
Alternatively, is there a better way to do this? Should I use a different request library? HTTParty doesn't have great support for auth headers like this. Thanks!
You need to explicitly require the RequestProxy.
require 'typhoeus'
require 'oauth'
require 'oauth/request_proxy/typhoeus_request'