Rails 5 api controller not receiving params sent by frontend app [duplicate] - ruby

I seem to be running into some issues making a GET request to an API endpoint. I know rails has some security going on behind the scenes. I'm using React-Rails and in my componentDidMount to make an ajax call to an API endpoint. I am passing in a X-Auth-Token in my headers too.
My console error:
XMLHttpRequest cannot load "/api/end/point..." Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
My ajax call is looking like
$.ajax({ url: "my/api/endpoint...", headers: {"X-Auth-Token": "My API token..."},
success: (response) => { console.log(response); } })

Because your frontend will do requests from any origin (any client), you have to enable CORS from any origin. Try
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
I use this in a rails 5 api application. Before rails 5 add rack-cors gem to your Gemfile. Anyway, restart your server.
rails 3/4
# config/application.rb
module YourApp
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
end
end

Related

Cross-Origin Request Blocked with Sinatra and ReactJS

I am building a simple Sinatra backend with ReactJS frontend. When I try to make request to a route in my Sinatra project from React app it gives me CORS error. I tried to enable CORS in my project like this but it didn't work:
require 'sinatra'
require 'sinatra/cross_origin'
require 'json'
configure do
enable :cross_origin
end
set :allow_origin, :any
set :allow_methods, [:get, :post, :options]
set :allow_credentials, true
set :max_age, "1728000"
set :expose_headers, ['Content-Type']
get '/' do
'Hello!'
end
post '/download' do
content_type :json
return {res: params['songs']}.to_json
end
So when I do a request like this from React:
axios.post('http://localhost:4567/download', {}, {
songs: this.state.songs
}).then(res => {
console.log(res.data)
})
I get a CORS error which looks like this:
And I get this error in the console:
What should I change in my Sinatra/React project to make this work so I can make requests from React to Sinatra?
See https://github.com/britg/sinatra-cross_origin#responding-to-options. You need to add your own code to manually handle OPTIONS requests — because the sinatra-cross_origin gem itself doesn’t actually handle OPTIONS requests. Specifically, you’d need to add this:
options "*" do
response.headers["Access-Control-Allow-Methods"] = "HEAD,GET,PUT,POST,DELETE,OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
200
end
I had the exact issue as you with Sinatra & React, after countless hours of searching I couldn't find any solution until I found this gem, https://github.com/jdesrosiers/sinatra-cors
Here's my solution which implements the basics:
require "sinatra/cors"
set :allow_origin, "*"
set :allow_methods, "GET,DELETE,PATCH,OPTIONS"
set :allow_headers, "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept, if-modified-since"
set :expose_headers, "location,link"

POST JSON response to HTTP request in Ruby

I'm running a Ruby app on Heroku. The app returns a JSON which is accessible when I go to the debugger of my browser. The JSON response is of the following template:
rates = {
"Aluminium" => price[1],
"Copper" => price_cu[1],
"Lead" => price_pb[1],
"Nickel" => price_ni[1],
"Tin" => price_sn[1],
"Zinc" => price_zn[1],
}
Sample response:
{
"Aluminium":"1765.50",
"Copper":"7379.00",
"Lead":"2175.00",
"Nickel":"14590.00",
"Tin":"22375.00",
"Zinc":"2067.00"
}
the code i wrote to achieve this is:
Test.rb
class FooRunner
def self.run!
#calculations_for_rates
rates.to_json
end
if __FILE__ == $0
puts FooRunner.run!
end
app.rb
require 'sinatra'
require './test.rb'
result = FooRunner.run!
File.open('output.json','w') do |f|
f.write result
end
content_type :json
result
When I try to access this link using
$.getJSON('app-url',function(data){
console.log(data);
});
it gives me an error saying
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Is there a way for me to directly access the JSON response by writing the JSON to the HTTP response?
So I am guessing that the page you are making the get request from is not served up by Sinatra. You can add the header Access-Control-Allow-Origin: * to that request to make it work.
This answer shows how to do it by either using response['Access-Control-Allow-Origin'] = * or headers( "Access-Control-Allow-Origin" => "*" )
That answer also lists this blog post as a reference to Cross Origin Resource Sharing in Sinatra.

401 Unauthorized when calling .ajax method in rails 3 application

I'm passing a ajax call to update data in my application through twitter bootstrap modal window. The ajax code is given below:
$(document).ready(function(){
var link=$('#link_hash').val();
$("#update_link").click(function(){
console.log("I'm here");
$.ajax({
url: "profiles/update_link",
type: "POST",
dataType: "html",
data: {link: link,data: $('#link_hash').val() },
success: function(data) {
// some code
},
error: function(data1) {
// some code
}
});
});
});
I have modifies route.rb file to match it to my controllers "update_link" method.
The code in my method is given below:-
def update_link
#link=Link.find_by_link(params[:link])
#tlink=Link.find_by_link(params[:data])
logger.info "=========kkkkkkkkkkkkkk=================================#{#link.inspect}"
logger.info "=========kkkkkkkkkkkkkk=================================#{#tlink.inspect}"
logger.info "=========kkkkkkkkkkkkkk=================================#{params.inspect}"
respond_to do |format|
if #tlink.nil?
#link.update_attributes(:link => params[:data])
...some code....
else
...some code...
end
end
end
end
So in the server log it's showing -
Started POST "/profiles/update_link" for 127.0.0.1 at 2013-02-20 12:08:20 +0530
Processing by ProfilesController#update_link as HTML
Parameters: {"link"=>"9bfzjp", "data"=>"9bfzjpaaa"}
WARNING: Can't verify CSRF token authenticity
Completed 401 Unauthorized in 6ms
So clearly "logger.info" is not showing up...Now after searching I was able to solve the WARNING but still 401 is present...How to solve this??
Thanks in advance....
According to your server log, you are not passing CSRF token, so rails automatically considers request to be malicious and flags it as unverified. default handling of unverified requests is to reset session. Can you comment out protect_from_forgery or add skip_before_filter :verify_authenticity_token to your controller to see if it the case?
If you want to include authenticity token in your ajax request (highly recommended) you can add it to headers in your ajax request:
headers: {
'X-Transaction': 'POST Example',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
}
Add skip_before_filter :authenticate_user! to your controller.

How to add response header in VHost or Passeneger (Ruby)

I have problem with Same Origin Policy. I want to make cross domain request - I found nice solution: http://www.w3.org/TR/cors/
But I don't want set header in Apache because I have there many domains and only one need it. Is it possible to add Access-Control-Allow-Origin header via Virtual Host or Passenger?
I do it, because I need use Redmine REST API (XHR) in Chrome/Mozilla plugin.
I had a similar requirement. If you want Redmine to serve these headers then you need to modify the Redmine source. I've written a blog post about doing this.
Credit to this blog post for most of the details.
I'll reproduce what I had to do here for convenience:
First let's adress the preflight check. I've added a whole new controller, just for this, at /app/controllers/cors_controller.rb. It looks like:
class CorsController < ApplicationController
skip_before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
def preflight
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, PUT'
headers['Access-Control-Allow-Headers'] = 'X-Requested-With, X-Prototype-Version, Content-Type'
headers['Access-Control-Max-Age'] = '1728000'
render :text => '', :content_type => 'text/plain'
end
end
Pretty simple stuff. I've then routed all OPTIONS requests to this controller in /config/routes.rb:
match '*path', :to => 'cors#preflight', :constraints => {:method => 'OPTIONS'}
Preflight checks taken care of, it's just a case of adding the headers to the main response using an after_filter in /app/controllers/application_controller.rb as suggested by Tom:
class ApplicationController < ActionController::Base
include Redmine::I18n
# ...
before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
#************ Begin Added Code ****************
after_filter :cors_set_access_control_headers
# For all responses in this application, return the CORS access control headers.
def cors_set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, PUT'
headers['Access-Control-Max-Age'] = "1728000"
end
#************* End Added Code *****************
#...
end

"Error validating client secret." 404 with Facebook Oauth and ruby

I am trying to implement facebook authentication for an app with warden, after the user allows facebook auth and redirects to my app callback with the token I get a 400 while consuming the api. My warden strategy is this:
class Facebook < Warden::Strategies::Base
def client
#client ||= OAuth2::Client.new MyApp::Facebook::AppID, MyApp::Facebook::AppSecret, :site => 'https://graph.facebook.com'
end
def params
#params ||= Rack::Utils.parse_query(request.query_string)
end
def authorize_url
client.web_server.authorize_url :redirect_uri => request.url, :scope => 'email,publish_stream'
end
def authenticate!
throw(:halt, [302, {'Location' => authorize_url}, []]) unless params['code']
facebook = client.web_server.get_access_token params['code'], :redirect_uri => request.url
rescue OAuth2::HTTPError => e
puts e.response.body
end
end
Strategies.add :facebook, Facebook
The result of printing the response body is this:
{"error":{"type":"OAuthException","message":"Error validating client secret."}}
I am pretty shure the app id and app secret are the ones provided by FB.
Thanks.
I've seen that error message many times. Here are the things I would double check:
your domain is the same as what you listed in the facebook callback url
the app id is correct (actually print this out on a page, sometimes y
the app secret is correct
Add redirect_uri while creating the object of facebook that will fix the issue.
Redirect the user to https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL
After user click allow, it'll hit our Redirect Uri
At that point we'll get the code and we need to do a server side HTTP Get to the following Url to exchange the code with our oAuth access token:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
Now at step 3, I kept on getting Http 400 response back.
So after some research, I found out that on that redirect_uri that we submitted on step 3 doesn't do anything but validate the request. Thus, the value need to match with step 2.
I also get the same error and i resolved by doing as below:
double check your client_id, client_secret, redirect_uri.
Add Accept: "application/json" header to thye request
fetch(
`https://graph.facebook.com/v15.0/oauth/access_token?client_id=${process.env.FACEBOOK_APP_ID}&redirect_uri=${process.env.FACEBOOK_REDIRECT_URI}&client_secret=${process.env.FACEBOOK_APP_SECRET}&code=${code}`,
{
method: "GET",
headers: {
Accept: "application/json",
},
}
)

Resources