A preflight request is an automatic HTTP request sent by the browser before the actual request in a Cross-Origin Resource Sharing (CORS) scenario. It is used to check whether the server allows the real request.
Browsers enforce CORS restrictions to protect users from security risks (e.g., cross-site request forgery). A preflight request is triggered when: 1. The request method is not a “simple” method (GET, POST, HEAD are simple; PUT, DELETE, etc., are not). 2. Custom headers are used (e.g., Authorization, Content-Type: application/json). 3. The request includes credentials (cookies, authentication tokens).
1. The browser automatically sends an HTTP OPTIONS request to the target server before the actual request. 2. The server responds with CORS headers to indicate which requests are allowed. 3. If allowed, the browser proceeds with the actual request.
Example: Preflight Request Client sends an OPTIONS request before making a PUT request: http
OPTIONS /api/data HTTP/1.1 Host: api.example.com Origin: https://client.example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Authorization, Content-Type
Server responds with allowed rules:
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://client.example.com Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600
A preflight request is skipped if the request is “simple”, meaning:
✅ Uses only GET, POST, or HEAD. ✅ No custom headers (except Content-Type: application/x-www-form-urlencoded, multipart/form-data, or text/plain). ✅ No authentication credentials (cookies, Authorization header).
Example of a simple request that does NOT trigger preflight:
http GET /api/users HTTP/1.1 Origin: https://client.example.com
A. Use “simple” requests
http Access-Control-Max-Age: 600 # Caches for 10 minutes
C. Move API Calls to the Same Origin
D. Enable CORS on the Server for Specific Origins
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Max-Age "600"
</IfModule>