I am implementing a router to process all web requests.
OPTIONS requests come in and I am responding with:
header('Access-Control-Allow-Origin: http://localhost:4000');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: authorization');
header('Access-Control-Allow-Credentials: true');
header('Vary: Origin');
And also I am sending all those for the GET/POST/PUT/DELETE requests.
Is sending those headers for those "real" requests unnecessary?
The Fetch standard is the (somewhat dry) source of truth for the CORS protocol; you can find answers to all your questions about CORS in there; see, in particular,
Some CORS response headers are only used in preflight responses:
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Max-Age
Access-Control-Allow-Local-Network
(which is part of Local Network Access, a recent extension to the CORS protocol)Other CORS response headers are used in both the preflight response and the actual response:
Is sending those headers for those "real" requests unnecessary?
Note that, if one or both of those headers (Access-Control-Allow-Origin
and Access-Control-Allow-Credentials
) are actually needed in the preflight response, they're also needed in the actual response.
Finally, one CORS response header is only used in the actual response: Access-Control-Expose-Headers
.
The case of the Vary
header is interesting. Since, in theory, responses to OPTIONS
requests are not cacheable (outside of browsers' preflight cache), the Vary
header should have no place in such responses. However, some caching intermediaries do allow their users to cache responses to OPTIONS
requests, and omitting the Vary
header from those responses may lead to Web cache poisoning.
This difficulty is a good indication that you shouldn't be implementing CORS by manually setting response headers. Instead, rely on a good CORS middleware library that can abstract all this complexity for you.