How do I use GET and POST on Github using access tokens? - ruby-on-rails

I am using OmniAuth to authenticate a user via Github. OmniAuth provides access tokens. Now I want to send the GET or POST request to Github. I don't want to use any gems, I want to do with Net::HTTP. I did it like this:
<%consumer = OAuth::Consumer.new("mshsD0jpgcYwwOEcTW5ZTA", "V6KTqllY5jS392pj4FNFCb5EiOM8DaFzVwr9cS54XQ", { :site => "https://api.github.com", :request_token_path => '/oauth/request_token', :access_token_path => '/oauth/access_token', :authorize_path => '/oauth/authorize', :scheme => :header })%>
<%access_token = OAuth::AccessToken.new(consumer,auth.token,auth.secret)%>
The same I previously did for Twitter worked fine but now I am getting the following error:
uninitialized constant ActionView::CompiledTemplates::OAuth
Even in the same application the same thing is working for Twitter but not for Github.
I searched through Google but found nothing that helped.

You should be using OAuth2 instead of OAuth. I'd actually recommend using Octokit, it's easy to use and Wynn works for GitHub now so part of his job is keeping it up to date. :)
If you want to use Net::HTTP (although I can't imagine why), you can actually do that without any gems. Just put the token you got from OmniAuth in the request's "Authentication" header.
require 'net/https'
require 'uri'
uri = uri = URI.parse("https://api.github.com/users/username")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = { "Authentication" => "token" }
request = Net::HTTP::Get.new(uri.request_uri, headers)
response = http.request(request)
response.body # => A string containing the JSON response

Seeing as you're already using Omniauth and are familiar with it, I'd recommend using the omniauth-github strategy: https://github.com/intridea/omniauth-github

Related

How to run cURL commands in Rails

I'm using Ruby on Rails 5 and I need to execute the following command in my application:
curl -F 'client_id=126581840734567' -F 'client_secret=678ebe1b3b8081231aab27dff738313' -F 'grant_type=authorization_code' -F 'redirect_uri=https://uri.com/' -F 'code=AQBi4L2Ohy3Q_N3V48OygFm0zb3gEsL985x5TIyDTNDJaLs93BwXiT1tyGYWoCg1HlBDU7ZRjUfLL5HVlzw4G-7YkVEjp6Id2WuqOz0Ylt-k2ADwDC5upH3CGVtHgf2udQhLlfDnQz5NPsnmxjg4bW3PJpW5FaQs8fn1ztgYp-ssfAf6IRt2-sI45ZC8cqqr5K_12y0Nq_Joh0H-tTfVyNLKatIxHPCqRDb3tfqgmxim1Q' https://api.instagram.com/oauth/access_token
so that it returns something like:
{"access_token": "IGQVJYS0k8V6ZACRC10WjYxQWtyMVRZAN8VXamh0RVBZAYi34RkFlOUxXZnTJsbjlEfnFJNmprQThmQ4hTckpFUmJEaXZAnQlNYa25aWURnX3hpO12NV1VMWDNMWmdIT3FicnJfZAVowM3VldlVWZAEViN1ZAidHlyU2VDMUNuMm2V", "user_id": 17231445640157812}
Is there a way to make Rails execute those types of commands? I was trying the following:
uri = URI.parse('https://api.instagram.com/oauth/access_token')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({
"client_id" => "126581840734567",
"client_secret" => "678ebe1b3b8081231aab27dff738313",
"grant_type" => "authorization_code",
"redirect_uri" => "http://nace.network/",
"code" => params[:code]
})
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end
but I get the following error:
end of file reached
in this line:
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end
You're using HTTPS, so you need to add this to your code:
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
res = http.request(request)
end
But if you don't need persistent connections, you could also use this:
res = Net::HTTP.post_form(uri,
"client_id" => "126581840734567",
"client_secret" => "678ebe1b3b8081231aab27dff738313",
"grant_type" => "authorization_code",
"redirect_uri" => "http://nace.network/",
"code" => params[:code]
)
Also, you could consider using a library like Faraday, which is a lot easier to deal with.
Edit
This is from TinMan's comment below, sound points.
Using cURL from inside Ruby or Rails is extremely valuable. There is an incredible amount of functionality inside cURL that isn't implemented in Rails or Ruby; Even Ruby's HTTP clients have a hard time replicating it, so cURL is very acceptable depending on the needs of the application. And, depending on the application, because cURL is in compiled C, it could easily outrun pure Ruby clients.
Curl is a means of issuing HTTP (or HTTPs) requests from the command line.
You don't want to use CURL in Rails. You want to issue HTTP requests from within Rails. Using curl is okay, it's one way to issue HTTP requests from with Rails.
We can refine that down further to, you want to issue HTTP requests from Ruby. Narrowing/distilling down to the most basic version of the problem is always good to do.
We knew all this already probably - still worth writing down for us all to benefit from!
Use HTTP in Ruby
We want to use a HTTP Client. There are many but, for this I'm going to use Faraday (a gem) 'cause I like it.
You've made a good start with Ruby's built in NET:HTTP but I prefer Faraday's DSL. It results in more readable and extendable code.
So, here is a class! I barely tested this so, use as a starting point. Make sure you write some unit tests for it.
# This is a Plain Old Ruby Object (PORO)
# It will work in Rails but, isn't Rails specific.
require 'faraday' # This require is needed as it's a PORO.
class InstagramOAuth
attr_reader :code
# The code parameter will likely change frequently, so we provide it
# at run time.
def initialize(code)
#code = code
end
def get_token
connection.get('/oauth/access_token') do |request|
request.params[:code] = code
end
end
private
def connection
#connection ||= Faraday.new(
url: instagram_api_url,
params: params,
ssl: { :ca_path => https_certificate_location }
)
end
def instagram_api_url
#url ||= 'https://api.instagram.com'
end
# You need to find out where these are for your self.
def https_certificate_location
'/usr/lib/ssl/certs'
end
def params
# These params likely won't change to often so we set a write time
# in the class like this.
{
client_id: '126581840734567',
client_secret: '678ebe1b3b8081231aab27dff738313',
grant_type: 'authorization_code',
redirect_uri: 'https://uri.com/'
}
end
end
# How do we use it? Like so
# Your big old authorisation code from your question
code = 'AQBi4L2Ohy3Q_N3V48OygFm0zb3gEsL985x5TIyDTNDJaLs93BwXiT1tyGYWoCg1HlBDU'\
'7ZRjUfLL5HVlzw4G-7YkVEjp6Id2WuqOz0Ylt-k2ADwDC5upH3CGVtHgf2udQhLlfDnQz'\
'5NPsnmxjg4bW3PJpW5FaQs8fn1ztgYp-ssfAf6IRt2-sI45ZC8cqqr5K_12y0Nq_Joh0H'\
'-tTfVyNLKatIxHPCqRDb3tfqgmxim1Q'
# This will return a Faraday::Response object but, what is in it?
response = InstagramOAuth.new(code).get_token
# Now we've got a Hash
response_hash = response.to_hash
puts 'Request made'
puts "Request full URL: #{response_hash[:url]}"
puts "HTTP status code: #{response_hash[:status]}"
puts "HTTP response body: #{response_hash[:body]}"
When I ran the snippet above I got the following. The class works, you just need to tweak the request params until you get what you want. Hopefully the class demonstrates how to send HTTP requests in Ruby/Rails.
Request made
Request full URL: https://api.instagram.com/oauth/access_token?client_id=126581840734567&client_secret=678ebe1b3b8081231aab27dff738313&code=AQBi4L2Ohy3Q_N3V48OygFm0zb3gEsL985x5TIyDTNDJaLs93BwXiT1tyGYWoCg1HlBDU7ZRjUfLL5HVlzw4G-7YkVEjp6Id2WuqOz0Ylt-k2ADwDC5upH3CGVtHgf2udQhLlfDnQz5NPsnmxjg4bW3PJpW5FaQs8fn1ztgYp-ssfAf6IRt2-sI45ZC8cqqr5K_12y0Nq_Joh0H-tTfVyNLKatIxHPCqRDb3tfqgmxim1Q&grant_type=authorization_code&redirect_uri=https%3A%2F%2Furi.com%2F
HTTP status code: 405
HTTP response body:
Additional Reading
. https://lostisland.github.io/faraday/usage/
. https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates

Quickblox Rails Signature

I am having a very hard time getting access to the quickblox API. Based on their documentation this code should work:
require 'base64'
require 'cgi'
require 'openssl'
require 'hmac-sha1'
# Application credentials
aPPLICATION_ID = 12345
aUTH_KEY = 'hidden'
aUTH_SECRET = 'hidden'
# Generate signature
timestamp = Time.now.in_time_zone('UTC').to_i
nonce = timestamp-425346
signature_string = "application_id=#{aPPLICATION_ID}&auth_key=#{aUTH_KEY}&nonce=#{nonce}&timestamp=#{timestamp}"
signature =Base64.encode64("#{ OpenSSL::HMAC.digest('sha1', signature_string, aUTH_SECRET) }")
# Post
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new("/session.json")
request.add_field('QuickBlox-REST-API-Version', '0.1.1')
request.add_field('Content-Type', 'application/json')
request.add_field('Accept', '*/*')
request.body = {"application_id" => aPPLICATION_ID, "auth_key" => aUTH_KEY, "nonce" => nonce, "timestamp" => timestamp, "signature" => signature }.to_json
response = http.request(request)
However I keep getting an error: {"errors":{"base":["Unexpected signature"]}}
Even when using their hurl: http://hurl.quickblox.com/ i get the exact same error. Very frustrating. What exactly am I doing wrong?
As it turns out, it looks like QuickBlox does not accept the signature has produced by ruby for some reason. QuickBlox even removed their own ruby gem (in which also generates this same error).
Right now the solution is to grab the token via a php script first then do your calls in ruby.
Check my stackoverflow answer on this issue here.
This mostly boils down to these two lines:
signature_string = "application_id=#{aPPLICATION_ID}&auth_key=#{aUTH_KEY}&nonce=#{nonce}&timestamp=#{timestamp}"
signature =Base64.encode64("#{ OpenSSL::HMAC.digest('sha1', signature_string, aUTH_SECRET) }")
You can check this quickblox_api gem too. It worked greatly for me.

How to get omniauth hash if I already have the access_token?

Currently I have it implemented like so.
def auth_hash
url = URI.parse('https://graph.facebook.com/me')
url.query = URI.encode_www_form('access_token' => #token, 'fields' => 'email, name, first_name, last_name, gender')
req = Net::HTTP::Get.new url.request_uri
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = nil
http.start do |get|
response = get.request(req)
end
response
end
My IOS app does the callbacks and sends the access token to authenticated with our server.
I use the method above and it returns the hash from the graph api and I get the user info perfectly.
This method that I've used but it's not utilizing omniauth. So my question is there a way to retrieve the omniauth hash using only the generated access_token (the token is generated by the facebook sdk and sends it to the server)?
I'm just trying to make sure I'm not reinventing the wheel using this method.
There are few ruby gems for authentication with Facebook and retrieving data from it.
Please refer this link : https://github.com/arsduo/koala ,
https://github.com/nov/fb_graph2
And for google use can use refer this link: https://github.com/zquestz/omniauth-google-oauth2

http Post request And declaration of authorization header in rails

I am trying to perform an HTTP authorization using Ruby on Rails. Here is what I'm trying:
res = http.post(uri.request_uri,
:Authorization => cobSessionToken,
"coBrandSessionCredential=loginToken=#{cobSessionToken}&userLogin=#{login}&userPassword=#{password}")
render :json => {"isValid" => true, "Body" => JSON.parse(res.body)}
This doesn't seem to work. How can I perform an authorization?
how about something like this?
url = URI.parse('https://my.url.com/path')
req = Net::HTTP::Post.new(url.path)
req.basic_auth 'user', 'pass'
req.use_ssl = true
req.form_data({'key1' => 'val1', 'key2' => 'val2'})
resp = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
puts resp
I would recommend using something like postman (its a free google program you can get at the google store) to make sure the error is not on the server side. Use Net:http it comes with ruby so you do not need to install it but you have to require it.
Require it by:
require "net/http"
require "uri"
Use this cheatsheet I think you need basic_auth.rb You will see how to form the request.

Instagram.get_access_token returns BadRequest

I'm trying to authenticate a user with Instagram gem. So I have a page with code param returned by instagram, and I only need to send it back with POST request. According to gem documentation I need to do something like:
get "/oauth/callback" do
response = Instagram.get_access_token(params[:code], :redirect_uri => CALLBACK_URL)
session[:access_token] = response.access_token
redirect "/feed"
end
so I have
def authenticate
response = Instagram.get_access_token(params[:code], :redirect_uri => "http://127.0.0.1:3000")
session[:access_token] = response.access_token
redirect "/feed"
end
And I'm getting
Completed 500 Internal Server Error in 957ms
Instagram::BadRequest (POST https://api.instagram.com/oauth/access_token/: 400):
app/controllers/instagram_controller.rb:25:in `authenticate'
I tried making curl request as per Instagram api documentation, and it works with the same params.
About client_id, I store those keys in instagram.rb in initializers, so it looks like
require "instagram"
Instagram.configure do |config|
config.client_id = "123345"
config.client_secret = "123123"
end
CALLBACK_URL = "http://127.0.0.1:3000"
Thanks a lot in advance.
Found the problem. So, I have devise in my app as well, and I didn't put "redirect_url" in config.omniauth over there. Exactly the same thing people talking about over here https://github.com/Instagram/instagram-ruby-gem/issues/22.
Thanks for help.

Resources