Preflight Request Failed

Preflight Request Failed

The error “CORS: preflight request failed” occurs when the browser sends a preflight request (an OPTIONS request) to the server, but the server either does not respond correctly or rejects the request.OPTIONS Preflight requests are part of the Cross-Origin Resource Sharing (CORS) mechanism and are triggered for certain types of cross-origin requests. Let’s break down why this happens, how to fix it, and best practices for handling preflight requests.


Why Does This Error Occur?

A preflight request is sent by the browser when:

  1. The request uses HTTP methods other than [GET, POST, HEAD]
  2. The request includes custom headers e.g.: Authorization Content-Type
  3. The Content-Type header is set to a value other than application/x-www-form-urlencoded multipart/form-data text/plain

If the server does not respond to the preflight request with the appropriate CORS headers, the browser will block the actual request and throw the error: “CORS: preflight request failed”.


How to Fix the Error

1. Ensure the Server Responds to Preflight Requests

The server must handle OPTIONS requests and include the necessary CORS headers in the response. Here’s how to configure this in different server environments:

Example in Node.js (Express):

const express = require('express');
const app = express();

// Handle preflight requests
app.options('/api/data', (req, res) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.send();
});

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello, CORS is enabled!' });
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

Example in Python (Flask):

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/data', methods=['GET', 'OPTIONS'])
def handle_data():
    if request.method == 'OPTIONS':
        response = jsonify()
        response.headers.add('Access-Control-Allow-Origin', '*')
        response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
        response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization')
        return response
    return jsonify(message="Hello, CORS is enabled!")

if __name__ == '__main__':
    app.run(port=3000)

Example in Nginx:

If you’re using Nginx as a reverse proxy, add the following to your configuration:

location /api/ {
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
        return 204;
    }
    proxy_pass http://backend-server;
}

2. Include the Correct Headers in the Preflight Response

The server must include the following headers in the preflight response:

  • Access-Control-Allow-Origin: Specifies which origins are allowed e.g.: * or https://example.com
  • Access-Control-Allow-Methods: Lists the HTTP methods allowed for the actual request e.g.: GET, POST, PUT, DELETE
  • Access-Control-Allow-Headers: Lists the headers allowed in the actual request e.g.: Content-Type, Authorization

Example Preflight Response:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization

3. Debugging Preflight Requests

If you’re unsure why the preflight request is failing, inspect the request and response using browser developer tools or a tool like Postman. Look for:

  • Missing or incorrect CORS headers in the preflight response.
  • Mismatched value of Access-Control-Allow-Origin
  • Incorrect Access-Control-Allow-Methods or Access-Control-Allow-Headers

Real-World Example: Handling Preflight Requests

Scenario:

You have a frontend application hosted on https://frontend.com that needs to send a PUT request with a custom Authorization header to a backend API hosted on https://backend.com The backend API does not handle preflight requests correctly, causing the error: “CORS: preflight request failed”.

Solution:

  1. Update the backend server to handle OPTIONS requests and include the necessary CORS headers.
  2. Ensure the Access-Control-Allow-Origin Access-Control-Allow-Methods Access-Control-Allow-Headers headers are correctly set in the preflight response.

Updated Frontend Code:

fetch('https://backend.com/api/data', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer token',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ key: 'value' })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Best Practices for Handling Preflight Requests

  1. Always Handle OPTIONS Requests: Ensure your server responds to OPTIONS requests with the correct CORS headers.
  2. Use Specific Origins: Avoid using * for Access-Control-Allow-Origin in production. Instead, specify the exact origins that are allowed.
  3. Limit Allowed Methods and Headers: Only allow the HTTP methods and headers that are necessary for your application.
  4. Test Thoroughly: Use browser developer tools or API testing tools to verify that preflight requests are handled correctly.

Conclusion

The Preflight Request Failed error indicates that the server did not respond correctly to the browser’s CORS preflight request, often due to missing or misconfigured CORS headers. To fix this, ensure that the server properly handles OPTIONS requests and includes the necessary Access-Control-Allow-* headers to match the client’s request while maintaining security.