Skip to content

OPTIONS does not actually handle CORS pre-flight requests #3027

@laurenceisla

Description

@laurenceisla

Problem

While adding Origin validation for CORS requests, we found out that our OPTIONS implementation does not actually handle pre-flight requests, at least not completely #2986 (comment).

This is how it works right now:

Successful request

$ curl -X OPTIONS "http://localhost:3000/projects" \
        -H "Access-Control-Request-Method: POST" \
        -H "Access-Control-Request-Headers: Content-Type" \
        -H "Origin: http://localhost" -i
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Fri, 27 Oct 2023 19:05:19 GMT
Server: postgrest/11.2.0 (8c9213d)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PATCH, PUT, OPTIONS, HEAD, POST
Access-Control-Allow-Headers: Authorization, Content-Type, Accept, Accept-Language, Content-Language
Access-Control-Max-Age: 86400

The actual response is given by the wai-cors library. We can notice because our implementation does not return pre-flight headers, only Access-Control-Allow-Origin. In summary, our OPTIONS does nothing here, the library does the response.

Failing request

$ curl -X OPTIONS "http://localhost:3000/projects" \
        -H "Access-Control-Request-Method: TRACE" \
        -H "Access-Control-Request-Headers: Content-Type" \
        -H "Origin: http://localhost" -i
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Fri, 27 Oct 2023 19:16:15 GMT
Server: postgrest/11.2.0 (8c9213d)
Access-Control-Allow-Origin: *
Allow: OPTIONS,GET,HEAD,POST,PUT,PATCH,DELETE

Only when it fails, our OPTIONS implementation goes through and returns this info. This happens because we set the library to not respond with an error and let the request continue:

, Wai.corsIgnoreFailures = True

This still fails the pre-flight (in Firefox and Chrome at least) because Access-Control-Allow-Methods is not set (different from Allow which has no meaning in CORS pre-flight).

Solution

We have two options here:

  • Let the library return the error which is a 400 with a predefined message indicating the problem.
  • Implement our own, which would mean to verify if the OPTIONS CORS request is pre-flight (with the required headers) and respond with a custom error indicating the problem.

Any of these would liberate the simple OPTIONS CORS request (not preflight) to work as we want. For instance, it could bring back the schema definition mentioned in #790.

Metadata

Metadata

Assignees

Labels

httphttp compliance

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions