rack-cors icon indicating copy to clipboard operation
rack-cors copied to clipboard

Access-Control-Allow-Origin is returned only if Origin header is set

Open monfresh opened this issue 12 years ago • 8 comments

Rails 3.2.13, Ruby 2.0.0, Mongoid config/application.rb:

...
config.middleware.use Rack::Cors do
      allow do
        origins '*'
        # location of your API
        resource '/api/*', :headers => :any, :methods => [:get, :post, :options, :put]
      end
    end

Using HTTPie:

http -h http://localhost:8080/api/organizations

Access-Control-Allow-Origin is NOT returned

If I set an Origin header:

http -h http://localhost:8080/api/organizations Origin:http://ohanapi.org

I get:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT
Access-Control-Allow-Origin: http://ohanapi.org

Is this expected? I was under the impression that Access-Control-Allow-Origin would be set to * even if no Origin was specified.

GitHub's API returns * when no Origin is specified. How can I get that behavior as well?

monfresh avatar May 31 '13 03:05 monfresh

+1

schorsch avatar Jun 05 '13 21:06 schorsch

I wonder what role this plays: http://www.w3.org/TR/access-control/#resource-implementation

aiwilliams avatar Jun 25 '13 13:06 aiwilliams

It think the current implementation is the correct behavior. Step one of the CORS spec states that any simple request without an Origin header is outside the scope of the CORS specification. (http://www.w3.org/TR/access-control/#resource-requests)

Having said that, I'm don't see any harm in possibly supporting this as an additional configuration (I'd like the default implementation to eventually match spec as much as possible).

Sorry for taking so long to respond to this. Is there a particular use case where this behavior is necessary? I'd like to understand under what circumstances why this behavior is desired.

cyu avatar Jul 16 '13 08:07 cyu

I agree the library should strictly implement the CORS specification.

It is interesting to note that responses from api.github.com have this header combination:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *

Reading the spec here, you'll find this Note in the discussion about supports credentials:

The string "*" cannot be used (as the value of the Access-Control-Allow-Origin header) for a resource that supports credentials.

My concern is further expressed in the discussion about Security Concerns. Namely, if a resource supports credentials, it should also reflect the requesting Origin as the Access-Control-Allow-Origin.

In other words, I think rack-cors has this right. Therefore, it should be difficult to do it wrong?

aiwilliams avatar Jul 16 '13 16:07 aiwilliams

Just thought I'd drop my 2c in here.

For responses which you want to consider public as far as cache control goes, it can be necessary to add in the Access-Control-Allow-Origin header, despite the lack of the Origin request header. Having this configurable would be excellent. We have an issue where Rack::Cache is storing a response that doesn't have the Access-Control-Allow-Origin header, and is returning it for requests even if they have the Origin request header.

snikch avatar Aug 27 '13 01:08 snikch

For the record, we solved the issue by adding a Vary: Origin header to all requests that could possibly be CORS.

snikch avatar Aug 27 '13 23:08 snikch

We couldn't use the workaround suggested by @snikch as adding Vary: Origin prevents our CDN from caching any requests, so we ended up writing another middleware to inject a fake Origin header into all requests before they hit rack-cors:

class InjectOriginHeaderMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    # Force rack-cors to always return Access-Control-Allow-Origin
    # by always setting the "Origin:" header in the request
    env['HTTP_ORIGIN'] ||= 'force-CORS'
    @app.call(env)
  end
end

In application.rb:

config.middleware.insert_before Rack::Cors, "InjectOriginHeaderMiddleware"

lsimoneau avatar Apr 13 '15 06:04 lsimoneau

This issue is 3 years old, but this strict interpretation is indeed causing us issues as described by folks above. In particular, we would like to cache a VERY specific set of headers as our response for our javascript files, regardless of whether the origin is set. By varying the responses based on the request, it is possible for us to have the wrong responses get set in our CDN's cache, which causes subsequent valid requests to fail.

We might have to manually add these headers as suggested, but I welcome other suggestions or options to force this header.

On a related note, imagine that we have a very particular domain (example.com) that we'd like to specify as a valid origin. So, we'd like to always respond with the header: Access-Control-Allow-Origin: http://example.com, regardless of which origin was used in the request. At present, even if we do specify a origin, if we specify an origin other than example.com, the CORS headers are not returned. I realize that this is to spec, but is there a way to force these headers to show up, even if the origin is incorrect?

Taytay avatar Jul 04 '18 18:07 Taytay