Sinatra and JSONP

05 Feb 2014

Sinatra is really cool for creating apis beacause of its simplicity, but some defaults can bring you trouble when creating a JSONP endpoint.

JSONP is widely used to execute cross domain requests and by default Sinatra will use rack-protection gem so your app is automatically protected by some vector attacks.

This defaults can cause you trouble when the client code sending the request adds the Referer header with a domain different from you app domain.

Imagine the following sinatra code:

1 require 'sinatra'
2 require 'sinatra/json'
4 get "/jsonp" do
5   json(%(do_something({ "some_name": "some value" })))
6 end

If you run the following spec then everything works fine:

1 it "returns ok" do
2   get "/jsonp"
3   expect(last_response).to be_ok
4 end

But when you add the Referer header to the request, it will fail with a 403 (Forbidden) status:

1 it "returns ok when referer is another site" do
2   get "/jsonp", {}, { "HTTP_REFERER" => "" }
3   expect(last_response).to be_ok
4 end

To avoid this issue you have to disable the json_csrf protection by doing this in your sinatra app:

1 set :protection, except: [ :json_csrf ]

After that the second spec will be success.

You can find the full example app on my github. The master branch has the failing spec, and the fixed branch has the configuration to remove json_csrf protection.