The Name's CORS. Rack::CORS.
Tags: beginners, ruby, rails, todayilearned
Published: 2019-07-17 22:41:42

My latest project required using Rails to create an API backend. Ruby has a nifty `--api` flag that creates a repo with only the folders you would need. It cuts down a lot of the extra folders you would get when normally creating a new Rails app. It also automatically adds a line into your gemfile to include Rack-CORS.

Following instructions, I uncommented `rack-cors` in my gemfile to make sure it was "working" and copy-pasted some extra code into my `application.rb` file "to allow CORS to work". Done. Cool.

As usual, I was absolutely baffled. What had I just done, what was anything actually doing, what did any of it mean and what even *was* the meaning of life?? I moved on and hoped I'd understand later on.

I never really got that explanation. So I decided to research it myself. I regretted it instantly.

---

##What is CORS?

Anytime you want to bring resources into your web app that come from different [origins](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin), you'd implement Cross-Origin Resource Sharing, or CORS for short. CORS has standardized the way we retrieve cross-origin resources. How? …

>["...it uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin."](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)

What this means is that CORS is going ahead and telling your browser which resources your app is allowed to access when it's trying to access a *resource that is not at its original domain* (aka cross-origin). 

And the only reason CORS even needs to do that is because of the Single-Origin Policy, which states that only resources from a single origin can be requested. Browsers abide by this policy by default for obvious security reasons. But that means we need to somehow figure out how to allow the cross-origin requests we do want to go through. 

We do that by including the right CORS headers into our request. 


*Side note:* JSONP (JSON with Padding) is another way to resolve the same-origin policy. Because HTML script tags are an exception to the cross-origin restrictions, JSONP simply turns data into an HTML script tag to bypass the single-origin policy. It's admittedly a bit “hacky” so not really used anymore unless a browser doesn't support CORS. [*](https://dev.socrata.com/docs/cors-and-jsonp.html) 

---

##What's Rack::CORS?

Rack::CORS is a middleware gem for Rack compatible web apps that helps you more easily implement CORS. It breaks the things down and turns making those cross-domain requests a cleaner and easier process. Plus, the error messages are super helpful.

###How To Use It

The [documentation](https://github.com/cyu/rack-cors) for Rack CORS is helpful in explaining what to add where, but if you don't know much about CORS in general, it can be difficult to understand what you're looking at.

First, as the documentation explains, you want to open your `config/application.rb` file and add something like this into your code:

```ruby
config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'example.com', 'localhost:3000'
    resource '/publicStuff/*', headers: :any, methods: [:get, :post]
    resource '/myStuff/*', headers: :any, methods: :any
  end
end
```

- The first line uses `insert_before 0` so Rack CORS can run before any other middleware that might interfere with it.

- Line three is where you define which origins your app will accept resources from. This will be the domain name of the origin(s) you want to let through.

- Line four is doing the same thing except we're defining the resource(s), *or path(s)*, that we want to allow through.

- In the same line you've defined your allowed resource path(s), you'll define which request parameters to allow. Most likely you'll be using the methods and headers parameters. If you want to allow multiple methods, you'd use the bracket notation to list your methods: `methods: [:get, :post, :options]`

Let's look at the above example again and break things down.

```ruby
config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'example.com', 'localhost:3000'
    resource '/publicStuff/*', headers: :any, methods: [:get, :post]
    resource '/myStuff/*', headers: :any, methods: :any
  end
end
```

- It allows requests from the `example.com` domain or from `localhost:3000`.

- The paths allowed are:

  - any path that starts with `/publicStuff/` and

  - the `/myStuff/` path.

    - These possible paths could look something like `example.com/publicStuff/records/` or `localhost:3000/myStuff/`.

- For the `'/publicStuff/'` path it allows requests with any header, but only allows requests with the GET and POST method.

- Requests for the `'/myStuff/'` path are allowed with any method *and* any header.

---

If you're creating a small app you'll only ever run on your own computer or localhost, you might not need to worry about defining specific origins and routes:

You might have noticed the `'*'` wildcard is a sort of 'all things go' symbol. Using the `'*'` wildcard when defining the origin would allow all requests from any origin. Same would apply when using the wildcard for your resource paths. With resource paths, you can either allow any and all resource paths, (`resource '*'`) or allow any extension of a specific path root (`resource '/examplepath/* '`).

When defining parameters, you'll instead want to use something like `headers: :any` and not the `'*'` wildcard. 

So if you were to exclusively use the `'*'` wildcard for your small localhost app it might look something like this: 

```ruby
config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: :any
  end
end
```


That's nice and simple. 

---

There's a lot more to CORS than what's written here, and could be a whole blog post, or two, on its own. So if the concept still feels a little shaky, that's ok! There's a lot going on there that you don't necessarily need to understand to be a good programmer, but if you can understand what these few lines are doing it'll make some of those fetch request errors make a lot more sense. 

Happy Coding!

---

[Same-origin policy - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin) 
[Cross-Origin Resource Sharing (CORS) - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
[CORS & JSONP](https://dev.socrata.com/docs/cors-and-jsonp.html) 
[Rack CORS Documentation](https://github.com/cyu/rack-cors)