Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

the Vary header does not seem to be set for CORS pre-flight checks that use the OPTIONS method #238

Open
regisebersole opened this issue Apr 23, 2022 · 1 comment

Comments

@regisebersole
Copy link

regisebersole commented Apr 23, 2022

Caveat: I may have a misconfiguration.

The vary option only seems to be honored for a specific resource for requests made with HTTP methods other than the pre-flight OPTIONS requests.

Whether or not the vary option is set for specific resource, no vary headers will be sent when the request uses the OPTIONS method.

This seems to cause a problem with Chrome where it caches the response for the period of time that is configured for max_age, which can be a problem for the use-case where Access-Control-Allow-Origin will neither be "*" nor a single static origin:
https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches
The work-around of course would be to set a very low max_age or to use a configuration option outside of rack-cors to set the vary header(s).

I recognize that this is a very old comment, but I wondered if it's still the design of rack-cors:
#73 (comment)

To reproduce, I am using rack-cors v1.1.1 and my config.ru is, where I currently have all http origins allowed (contrary to the nature of this issue) but would like to make the origins a conditional depending on a dynamic list of configured OIDC client URLs so that it will not simply be "*":

require 'rack/cors'
use Rack::Cors do
  allow do
    origins /\Ahttp.*/ # this should be a lookup for configured http and https OIDC clients
    resource '/oauth/*', headers: :any, methods: [:get, :post],
      max_age: 600,
      vary: ['Origin']
  end
end

require ::File.expand_path('../config/environment', __FILE__)
run Rails.application

For an example of how Google responds:

curl 'https://openidconnect.googleapis.com/v1/userinfo' \
  -X 'OPTIONS' \
  -H 'authority: openidconnect.googleapis.com' \
  -H 'accept: */*' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'access-control-request-headers: authorization,content-type' \
  -H 'access-control-request-method: POST' \
  -H 'cache-control: no-cache' \
  -H 'origin: http://localhost:8080/callback' \
  -H 'pragma: no-cache' \
  -H 'referer: http://localhost:8080/callback' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: same-site' \
  --compressed -v 2>&1

Where Google replies with:

vary: origin
vary: referer
vary: x-origin
access-control-allow-origin: http://localhost:8080/callback
access-control-allow-methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
access-control-allow-headers: authorization,content-type
access-control-max-age: 3600
@istvanp
Copy link

istvanp commented Jan 10, 2023

I monkey patched it as such:

module Rack
  class Cors
    class Resource
      def to_preflight_headers(env)
        h = to_headers(env)
        h.merge!('Vary' => vary_headers.join) # <== The patch

        if env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
          h.merge!('Access-Control-Allow-Headers' => env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS])
        end
        h
      end
    end
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants