Skip to content

CORS headers and OPTIONS requests #410

@david-crespo

Description

@david-crespo

NOTE: this problem disappears if we serve console API and external API from the same origin and instead use, e.g., subdomains or an /api route prefix to distinguish the two.


Serving the console from Nexus is almost working — it can send the HTML response and serve the static assets — but if console API and external API are going to be served from different origins, we need to set CORS headers in order to tell the browser the console is allowed to talk to the API.

We can hack the Access-Control-Allow-Origin header in easily enough, but there's another issue that's more interesting. the browser likes to do a preflight OPTIONS request on cross-origin requests to confirm it can do whatever it's trying to do, but they 405 because we do not explicitly define OPTIONS as an allowed method on our endpoint handlers (nor would we want to).

Other frameworks seem to handle this globally with a middleware that can respond to OPTIONS requests for any endpoint. In axum/tower it's built in, but in rocket and actix the crates are 3rd-party:

rocket_cors suggests an interesting option of using extractors (analogous to guards in rocket) but you're still explicitly annotating every route. It would be easy to forget, and I don't see why we would want to except any endpoints from the behavior. Also that still probably wouldn't work because I bet we don't even get to the extractors if the request method is not explicitly allowed.

As the MDN link says, basically all we need to be able to do is respond to OPTIONS requests with an empty body and some headers:

HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

I wonder how much we should care about the value of allow-methods being specific to the endpoint. It may well be fine to respond POST, GET, PUT, OPTIONS, DELETE to everything, which would make things easier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions