How to test CORS with Plug/Phoenix

So you have setup your API to accept CORS requests on certain paths on your API using cors_plug or corsica and you are wondering how you test this with ExUnit.

Back to basics: Does the endpoint actually work?

Well the first thing to do is to check if your endpoint is actually working with CORS.

You can do this via cURL:

curl http://localhost:4000/api/posts -v -H "Origin: https://example.com"

You will need to change the URL to your API Endpoint and your Origin to the URL you have allowed to access this endpoint.

If you would like to test this with an example endpoint, I’ve setup a heroku app at https://cors-example-phoenix.herokuapp.com/api/posts you can try.

You should then see the output of the command, hopefully containing the access-control-allow-origin header:

*   Trying ::1:4000...
* TCP_NODELAY set
* connect to ::1 port 4000 failed: Connection refused
*   Trying 127.0.0.1:4000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4000 (#0)
> GET /api/posts HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.67.0
> Accept: */*
> Origin: https://example.com
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< server: Cowboy
< date: Thu, 19 Dec 2019 14:17:33 GMT
< content-length: 222222
< content-type: application/json; charset=utf-8
< cache-control: max-age=0, private, must-revalidate
< access-control-allow-credentials: true
< access-control-allow-origin: https://example.com
< x-request-id: 3ngsmtk913a87kadq00017l8

If it does not contain the access-control-allow-origin header then the request either did not go through CORS correctly (failed to validate) or something else is going on. Corsica (which I recommend) supports logging which I highly recommend you enable when playing around with cors in dev mode as it’ll help you understand what is actually going on under the hood.

With corsica, you can see this in the logs:

[debug] Simple CORS request from Origin "https://foobar.com" is not allowed

If it does work and you do have the access-control-allow-origin header, change the Origin to something that DOES NOT match the origin you’ve set in your app and you shouldn’t see the header.

Testing with ExUnit

Your test can now look like this:

test "CORS will only work with example.com", %{conn: conn} do
  assert conn
         |> put_req_header("origin", "https://example.com")
         |> get("/api/posts", %{q: "90210"})
         |> get_resp_header("access-control-allow-origin") == ["https://example.com"]

  assert conn
         |> put_req_header("origin", "https://foobar.com")
         |> get("/api/posts", %{q: "90210"})
         |> get_resp_header("access-control-allow-origin") == []
end

As you can see, we use put_req_header("origin", "https://foobar.com") before making the request to set the origin as the URL we want to test. Since ExUnit actually starts a proper web server with Cowboy then does routing with Plug (if using Phoenix), we can test things like this super easily.

I’ve got an example repo setup on Github.