Handling CORS issues in your Rails API

Anyone who has ever attempted to write an API will at some point come across a CORS error when an attempting to make a CRUD request to a server. For anyone unaware, CORS refers to ‘Cross origin resource sharing’ and it is essentially how the server filters out requests from an origin other than itself.

If you’re building an application on a single host, this is not something you would generally need to concern yourself with as any request spawned from the front end will likely be made to the same domain. However, when building an API, you need to either expect requests made from any origin, or have a list of origins that are white-listed.

Whilst this post was made with reference to an API built on Rails, hopefully the content will be beneficial, regardless of the underlying language.

More commonly these days, before a CRUD request is made to the server, an OPTIONS request is first made. This request checks the server to ensure that the CRUD request which will subsequently made is valid. For example, you may be making an update (PUT/PATCH) request to the server to update a record in your database. The OPTIONS request will first be made to ensure that the server in question allows PUT requests and that the domain the request is being made from is allowed.

If your request fails to meet the requirements set by the server, you will likely see this error in your console;

Response to preflight request doesn't pass access control check: 

This error is likely down to your request not meeting the access-control criteria set by the server. Generally there are 4 access controls which need to be set correctly in order for the preflight request to pass. These are;

Access-Control-Allow-Origin

This is refers to the origin that the request can be made from, this can be wildcarded with an asterisk * which will allow requests from any domain;

Access-Control-Allow-Origin: *

Whilst, this is a perfectly valid thing to do. If you do not plan on exposing your API to the world, it would be better to explicitly set the origins you expect requests to be made from.

Access-Control-Allow-Origin: https://www.foo.com 

Access-Control-Allow-Headers

This refers to the headers which the server will allow. You can wildcard this to allow all headers or separate the headers with a comma.

Access-Control-Allow-Headers: origin, content-type

Access-Control-Allow-Methods

This refers to the request methods that can be made to the server. This is generally the CRUD request types such as GET(view), POST(insert), PUT/PATCH(update) and DELETE(delete). These values should be separated with a comma.

Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS

Access-Control-Allow-Credentials

This is a boolean value that when if true will allow cookies to be sent with the request. By default, this is false as cookies are not sent with CORS requests.

Access-Control-Allow-Credentials: true

Unless, you have a specific requirement not to do so, I would recommend using some form of middleware to serve these headers for you. This way, requests which do not meet the specified criteria are filtered out before they make it to your application layer and then all you need to concern yourself with is the handling of the data. If your API is built upon Rails, I recommend adding the Rack-Cors gem to your application. It is fairly straightforward to configure as all you need to do is ensure the gem is added to your gemfile and the following is included in your application.rb file.

#application.rb
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end

In the above example, I am pretty much letting all requests though, providing they are GET, POST or OPTION requests.

Hopefully, that will give you a brief understanding of how to deal with the more common CORS issues you may come across in your rails api.