Home

Awesome

Rack CORS Middleware Build Status

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 further explanations on MDN

Installation

Install the gem:

gem install rack-cors

Or in your Gemfile:

gem 'rack-cors'

Configuration

Rails Configuration

For Rails, you'll need to add this middleware on application startup. A practical way to do this is with an initializer file. For example, the following will allow GET, POST, PATCH, or PUT requests from any origin on any resource:

# config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :patch, :put]
  end
end

NOTE: If you create application with --api option, configuration is automatically generated in config/initializers/cors.rb.

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). Basic setup examples for Rails 5 & Rails 6 can be found in the examples/ directory.

See The Rails Guide to Rack for more details on rack middlewares or watch the railscast.

Read more about it here in the Rails Guides

Rack Configuration

NOTE: If you're running Rails, adding config/initializers/cors.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

Configuration Reference

Middleware Options

Origin

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, like \Ahttps:\/\/example\.com\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/*). A resource can take the following options:

Common Gotchas

Origin Matching

When specifying an origin, make sure that it does not have a trailing slash.

Testing Postman and/or cURL

Positioning in the Middleware Stack

Positioning of Rack::Cors in the middleware stack is very important. In the Rails example above we put it above all other middleware which, in our experience, provides the most consistent results.

Here are some scenarios where incorrect positioning have created issues:

You can run the following command to see what the middleware stack looks like:

bundle exec rails middleware

Note that the middleware stack is different in production. For example, the ActionDispatch::Static middleware will not be part of the stack if config.serve_static_assets = false. You can run this to see what your middleware stack looks like in production:

RAILS_ENV=production bundle exec rails middleware

Serving static files

If you trying to serve CORS headers on static assets (like CSS, JS, Font files), keep in mind that static files are usually served directly from web servers and never runs through the Rails container (including the middleware stack where Rack::Cors resides).

In Heroku, you can serve static assets through the Rails container by setting config.serve_static_assets = true in production.rb.

Custom Protocols (chrome-extension://, ionic://, etc.)

Prior to 2.0.0, http://, https://, and file:// are the only protocols supported in the origins list. If you wish to specify an origin that has a custom protocol (chrome-extension://, ionic://, etc.) simply exclude the protocol. See issue.

For example, instead of specifying chrome-extension://aomjjhallfgjeglblehebfpbcfeobpga specify aomjjhallfgjeglblehebfpbcfeobpga in origins.

As of 2.0.0 (currently in RC1), you can specify origins with a custom protocol.

Rails 6 Host Matching

Rails 6 will block requests from unauthorized hosts, and this issue can be confused as a CORS related error. So in development, if you're making requests using something other than localhost or 127.0.0.1, make sure the server host has been authorized. More info here