JSON parameters not available in request hash (Rails, omniauth-google-oauth2 gem) - ruby-on-rails

Overview
I want to implement the Google OAuth2 server side (hybrid) with the Omniauth Google OAuth2 Gem (0.2.6). However, the code parameter I send to my app does not get added to the request.params hash. Thus, OmniAuth throws an error, as it can't find the code.
Details
After retrieving the auth code from Google I send it to the server (by AJAX):
// Send the code to the server
$.ajax({
type: 'POST',
url: '/auth/google_oauth2/callback',
contentType: 'application/json',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: JSON.stringify(password_result)
});
This throws the error:
"error" : "invalid_request",
"error_description" : "Missing required parameter: code"
After going through the stack, I figured out the following:
As long as I have 'application/json' set as content Type, Rack parses the params correctly and the env object contains the parsed parameters:
"action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"}
However, the request.params hash remains empty. Since OmniAuth checks for request.params['code'], this is the source of the error.
request.POST is empty, which from looking at the source code of Rack is the underlying cause for the empty request.params hash.
When sending the code in standard format as data:"code="+authResult['code'], the parameter is available in the request.params hash. (I get a strange undefined route error then, but this is a different issue.)
Questions
Now, even though I can avoid the issue by not using JSON, I'm still very intereted in the answers to the following questions:
Why is the code parameter not available in request.POST/request.params, even though it gets parsed correctly?
Is there a way to fix this, so I can still send the auth code in JSON to my app?
I've spent two afternoons trying to get the answers myself, but haven't really gotten to a good conclusion so far.

omniauth-google-oauth2 tries to get the auth code from the Rack::Request.params hash. However, Rack apparently does not have JSON parsing built-in. Params calls POST which then calls form_data? which only looks for application/x-www-form-urlencoded or multipart/form-data. It then also tries parseable_data?, which does not parse JSON either. Seems like Rack does not support JSON out of the box, also look at this answer.
The "action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"} hash works because this is done by rails ActionDispatch::Request, which subclasses Rack::Request. However because The omniauth gem is included in your app as a Rack middleware, it does not know of the ActionDispatch request object.
The question remains why this example uses JSON.
Possible solutions:
money-Patch JSON Support into Rack - not recommended
just use application/x-www-form-urlencoded - recommended

Related

Interpolation with httparty request in rails

I want to make a http request (using httparty gem) to facebook graph to check if a token which comes form the client is valid or not, but I suppose that interpolation doesn't work with httparty
response = HTTParty.get("https://graph.facebook.com/me?access_token=#{params[:access_token]}")
render json: response
but this gives me the response
{"error":{"message":"Bad signature","type":"OAuthException","code":1}}
Am I missing something?
I suppose that interpolation doesn't work with httparty
Interpolation is a Ruby syntax feature; your string gets interpolated before it's ever passed to HTTParty.
You could have debugged this by inspecting the URL:
uri = "https://graph.facebook.com/me?access_token=#{params[:access_token]}"
Rails.logger.info(uri)
response = HTTParty.get(uri)
Regardless, when using query parameters with HTTParty, you shouldn't use interpolation anyway. You should pass them with the :query option, which will ensure that the parameters are encoded correctly:
response = HTTParty.get( "https://graph.facebook.com/me",
query: { access_token: params[:access_token] })
However, I'm not certain this will actually fix your problem. There's a good chance the problem is really somewhere else in your OAuth flow--there's a lot of room for error when working with OAuth.

HTTParty get request ignores query params

I'm trying to make a GET request with a quersytring, however, HTTParty is ignoring my params. For example, I'm doing something like this:
headers = {"User-Agent"=>"whatever", "Authorization"=>"whatever"}
options = {"sport" => "mlb" }
HTTParty.get("https://www.erikberg.com/events.json", query: options, headers: headers)
The response should be empty since yesterday there wasn't any MLB game going on. I checked with curl and worked properly. However, when I use this gem I'm getting NBA games (ignoring the param sport). I asked to the owner of the API and he told me I'm getting two redirects (302, 301).
Any clue of what is failing here? Is my request really using https?
Best regards!

Rack + Sinatra + Post Request Parsing

How can prevent Rack request parser for post request to filter out params with empty array value?
my params consist of something like {'imp_key' => [], 'notified' => 'true'}. However rack parser removed imp_key and I get only notified as params but I want to get all params I have send to it.
I am running into the same issue and can confirm it is a problem. I've traced it down to lib/rack/test/utils.rb:19 in build_nested_query. Any parameters with values of empty arrays are getting stripped there
EDIT: This appears to be an open issue with rack-test. See the Github issue

Make Rails parse JSON from XDR Cross-Domain requests with content-type: nil

I'm building a client side application which cross-domain posts JSON, using CORS, to a Rails 3.2 application on a different server. Unfortunately, we need to support IE9, which means that we're falling back to using XDomainRequest (XDR) to send our cross-domain requests in IE.
The major limitation of XDR is that it doesn't support setting headers like 'Content-type', which means the Rails server doesn't know that it's receiving JSON, so doesn't parse it.
I got around this briefly by using jQuery.param to send the data as url encoded form data. However, some of the data we need to send is nested GeoJSON, which gets garbled by jQuery.param, so I have to send the POST body as JSON.
In config/initializers/wrap_parameters.rb I've set:
ActiveSupport.on_load(:action_controller)
wrap_parameters format: [:json, nil]
end
… so ActionController nests parameters inside model_name when the content-type is nil.
However, I still need Rails to try to JSON.parse() the data from requests where "Content-type" => nil. I could just manually do this in the controllers which need it (which isn't very clean), but I was hoping I would be able to make Rails do it for all {content-type: nil} requests.
I've been looking through the Rails source, and what I've found doesn't make me very hopeful. This method seems to be hard coded to check for :json, and parse if so, meaning I can't modify this from config:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/params_parser.rb#L43
Can anyone come up with a clever solution?

Rails: Pass Params Through Ajax

I need to pass params through javascript back to the server. At the moment, I pass them into javascript like so:
sendParams("<%= params[:q].to_json %>");
And then send them back like this:
function sendParams(q){
$.ajax({
url: '/mymodel/myaction',
type: 'post',
data: {'q':q},
contentType: 'json'
});
}
In my controller, I try to use them like I would any other params:
MyModel.where(params[:q])
But the params are coming back empty, even though firebug shows this in the POST tab:
q=%7B%26quot%3Bc%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Ba%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bname%26quot%3B%3A%26quot%3Btitle%26quot%3B%7D%7D%2C%26quot%3Bp%26quot%3B%3A%26quot%3Bcont%26quot%3B%2C%26quot%3Bv%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bvalue%26quot%3B%3A%26quot%3B2%26quot%3B%7D%7D%7D%7D%2C%26quot%3Bs%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bname%26quot%3B%3A%26quot%3Bvotes_popularity%26quot%3B%2C%26quot%3Bdir%26quot%3B%3A%26quot%3Bdesc%26quot%3B%7D%7D%7D
Any idea why this information isn't getting processed by the where clause? What can I do to make the params Rails readable again?
UPDATE:
Started POST "/publications/search?scroll=active&page=6" for 127.0.0.1 at 2013-0
2-12 22:55:24 -0600
Processing by PublicationsController#index as */*
Parameters: {"scroll"=>"active", "page"=>"6"}
UPDATE 2:
The problem is apparently stemming from contentType. When I remove it, then q is sent as a Rails parameter. Unfortunately, q is still in JSON, resulting in the error:
undefined method `with_indifferent_access' for #<String:0x686d0a8>
How can I convert JSON to a params hash?
Your data parameter is wrong.
You have
data: {'q':q},
It should be
data: {q: 'q'},
There were a couple of issues that needed to be resolved for this to work. First, q wasn't being sent as a parameter to Rails, even though it was posting. The reason was because it was being treated as JSON data rather than as a parameter. I fixed this by removing the line:
contentType: 'json'
After that, the AJAX properly sent 'q', but Rails had trouble using it as it was in JSON. I had to parse it with ActiveSupport::JSON.decode, but this was throwing a 737: unexpected token error. I ran the code through (JSONlint)[http://jsonlint.com/], and it turns out that all the quotation marks had been escaped.
From there, there were two solutions. The obvious one was to use .html_safe like so:
sendParams("<%= params[:q].to_json.html_safe %>");
But this caused problems when the user inputed quotes. The safer alternative was to decode the escaped HTML entities after they were passed back to Rails like so:
ActiveSupport::JSON.decode(CGI.unescapeHTML(params[:q]))
And this did the trick.

Resources