Rack::Cors
provides support for Cross-Origin Resource Sharing (CORS) for Rack compatible web applications.
The CORS spec allows web applications to make cross domain AJAX calls without using workarounds such as JSONP. See Cross-domain Ajax with Cross-Origin Resource Sharing
Install the gem:
gem install rack-cors
Or in your Gemfile:
gem 'rack-cors'
Put something like the code below in config/application.rb
of your Rails application. For example, this will allow GET, POST or OPTIONS requests from any origin on any resource.
module YourApp
class Application < Rails::Application
# ...
# Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
# Rails 3/4
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
end
end
We use insert_before
to make sure Rack::Cors
runs at the beginning of the stack to make sure it isn't interfered with by other middleware (see Rack::Cache
note in Common Gotchas section). Check out the rails 4 example and rails 3 example.
See The Rails Guide to Rack for more details on rack middlewares or watch the railscast.
NOTE: If you're running Rails, updating in config/application.rb
should be enough. There is no need to update config.ru
as well.
In config.ru
, configure Rack::Cors
by passing a block to the use
command:
use Rack::Cors do
allow do
origins 'localhost:3000', '127.0.0.1:3000',
/\Ahttp:\/\/192\.168\.0\.\d{1,3}(:\d+)?\z/
# regular expressions can be used here
resource '/file/list_all/', :headers => 'x-domain-token'
resource '/file/at/*',
methods: [:get, :post, :delete, :put, :patch, :options, :head],
headers: 'x-domain-token',
expose: ['Some-Custom-Response-Header'],
max_age: 600
# headers to expose
end
allow do
origins '*'
resource '/public/*', headers: :any, methods: :get
# Only allow a request for a specific host
resource '/api/v1/*',
headers: :any,
methods: :get,
if: proc { |env| env['HTTP_HOST'] == 'api.example.com' }
end
end
- debug (boolean): Enables debug logging and
X-Rack-CORS
HTTP headers for debugging. - logger (Object or Proc): Specify the logger to log to. If a proc is provided, it will be called when a logger is needed. This is helpful in cases where the logger is initialized after
Rack::Cors
is initially configured, likeRails.logger
.
Origins can be specified as a string, a regular expression, or as '*' to allow all origins.
*SECURITY NOTE: Be careful when using regular expressions to not accidentally be too inclusive. For example, the expression /https:\/\/example\.com/
will match the domain example.com.randomdomainname.co.uk. It is recommended that any regular expression be enclosed with start & end string anchors (\A\z
).
Additionally, origins can be specified dynamically via a block of the following form:
origins { |source, env| true || false }
A Resource path can be specified as exact string match (/path/to/file.txt
) or with a '*' wildcard (/all/files/in/*
). To include all of a directory's files and the files in its subdirectories, use this form: /assets/**/*
. A resource can take the following options:
- methods (string or array or
:any
): The HTTP methods allowed for the resource. - headers (string or array or
:any
): The HTTP headers that will be allowed in the CORS resource request. Use:any
to allow for any headers in the actual request. - expose (string or array): The HTTP headers in the resource response can be exposed to the client.
- credentials (boolean, default:
false
): Sets theAccess-Control-Allow-Credentials
response header. Note: If a wildcard (*
) origin is specified, this option cannot be set totrue
. Read this security article for more information. - max_age (number): Sets the
Access-Control-Max-Age
response header. - if (Proc): If the result of the proc is true, will process the request as a valid CORS request.
- vary (string or array): A list of HTTP headers to add to the 'Vary' header.
Incorrect positioning of Rack::Cors
in the middleware stack can produce unexpected results. The Rails example above will put it above all middleware which should cover most issues.
Here are some common cases:
-
Serving static files. Insert this middleware before
ActionDispatch::Static
so that static files are served with the proper CORS headers (see note below for a caveat). NOTE: that this might not work in production environments as static files are usually served from the web server (Nginx, Apache) and not the Rails container. -
Caching in the middleware. Insert this middleware before
Rack::Cache
so that the proper CORS headers are written and not cached ones. -
Authentication via Warden Warden will return immediately if a resource that requires authentication is accessed without authentication. If
Warden::Manager
is in the stack beforeRack::Cors
, it will return without the correct CORS headers being applied, resulting in a failed CORS request. Be sure to insert this middleware before 'Warden::Manager`.
To determine where to put the CORS middleware in the Rack stack, run the following command:
bundle exec rake middleware
In many cases, the Rack stack will be different running in production environments. For example, the ActionDispatch::Static
middleware will not be part of the stack if config.serve_static_assets = false
. You can run the following command to see what your middleware stack looks like in production:
RAILS_ENV=production bundle exec rake middleware