I spent some time being confused as to the purpose of the preflight request but I think I’ve got it now.
The key insight is that preflight requests are not a security thing. Rather, they’re a not-changing-the-rules thing.
Preflight requests have nothing to do with security, and they have no bearing on applications that are being developed now, with an awareness of CORS. Rather, the preflight mechanism benefits servers that were developed without an awareness of CORS, and it functions as a sanity check between the client and the server that they are both CORS-aware. The developers of CORS felt that there were enough servers out there that were relying on the assumption that they would never receive, e.g. a cross-domain DELETE request that they invented the preflight mechanism to allow both sides to opt-in. They felt that the alternative, which would have been to simply enable the cross-domain calls, would have broken too many existing applications.
There are three scenarios here:
Old servers, no longer under development, and developed before CORS. These servers may make assumptions that they’ll never receive e.g. a cross-domain DELETE request. This scenario is the primary beneficiary of the preflight mechanism. Yes these services could already be abused by a malicious or non-conforming user agent (and CORS does nothing to change this), but in a world with CORS the preflight mechanism provides an extra ‘sanity check’ so that clients and servers don’t break because the underlying rules of the web have changed.
Servers that are still under development, but which contain a lot of old code and for which it’s not feasible/desirable to audit all the old code to make sure it works properly in a cross-domain world. This scenario allows servers to progressively opt-in to CORS, e.g. by saying “Now I’ll allow this particular header”, “Now I’ll allow this particular HTTP verb”, “Now I’ll allow cookies/auth information to be sent”, etc. This scenario benefits from the preflight mechanism.
New servers that are written with an awareness of CORS. According to standard security practices, the server has to protect its resources in the face of any incoming request — servers can’t trust clients to not do malicious things. This scenario doesn’t benefit from the preflight mechanism: the preflight mechanism brings no additional security to a server that has properly protected its resources.