# How to Configure CORS Headers for Cross-Origin API Requests: A Server-Side Guide

> Learn to configure CORS headers on your server to allow cross-origin API requests and avoid browser blocks. Fix Access-Control-Allow-Origin errors with this server-side guide.

- Repository: [Python Software Foundation/requests](https://github.com/psf/requests)
- Tags: how-to-guide
- Published: 2026-02-19

---

**Cross-Origin Resource Sharing (CORS) errors occur when browsers block API responses that lack proper `Access-Control-Allow-Origin` headers, and these headers must be configured on the server hosting the API rather than in client-side HTTP libraries like Python requests.**

When your web application attempts to fetch data from an API on a different domain, the browser enforces CORS policies that prevent access unless the server explicitly permits cross-origin requests. This guide explains how to properly configure CORS headers using popular Python frameworks, while referencing the `psf/requests` source code to clarify why the HTTP client library cannot resolve these browser-enforced restrictions.

## Understanding Why Browsers Block Cross-Origin Requests

CORS is a security mechanism enforced by **client-side browsers**, not by HTTP client libraries. When a browser sends a request to a different origin (domain, protocol, or port), it first performs a *pre-flight* `OPTIONS` request for non-simple requests, or checks the response headers of simple requests. If the server response does not contain the required `Access-Control-Allow-Origin` header, the browser blocks the response entirely and displays the CORS policy error.

The Python `requests` library, as implemented in [`src/requests/api.py`](https://github.com/psf/requests/blob/main/src/requests/api.py), functions as a generic HTTP client that builds outgoing requests and handles responses, but it operates outside the browser's security sandbox. The library's public `request()` function delegates to a `Session` object defined in [`src/requests/sessions.py`](https://github.com/psf/requests/blob/main/src/requests/sessions.py), while header handling logic resides in [`src/requests/models.py`](https://github.com/psf/requests/blob/main/src/requests/models.py) within the `Request` object. None of these modules add or enforce CORS headers because CORS validation occurs after the response leaves the server and reaches the browser.

## Why the Requests Library Cannot Configure CORS Headers

The `requests` library architecture demonstrates why CORS configuration is impossible from the client side. In [`src/requests/api.py`](https://github.com/psf/requests/blob/main/src/requests/api.py), the library provides the entry point for HTTP calls but focuses solely on constructing valid HTTP requests and parsing responses. The `Request` class in [`src/requests/models.py`](https://github.com/psf/requests/blob/main/src/requests/models.py) stores headers as generic key-value pairs without any CORS-specific logic, and [`src/requests/sessions.py`](https://github.com/psf/requests/blob/main/src/requests/sessions.py) manages connection pooling and request dispatch.

Since CORS policies are enforced by the browser's rendering engine after receiving the HTTP response, no amount of client-side header manipulation in `requests` can bypass the restriction. The browser requires specific `Access-Control-Allow-*` headers in the **server's response** to grant permission for cross-origin access.

## How to Configure CORS Headers on Your API Server

To resolve CORS errors, you must modify the server hosting the API to emit the appropriate headers. Below are implementations for common Python web frameworks.

### Flask

Use the `flask_cors` extension to automatically inject CORS headers and handle pre-flight `OPTIONS` requests:

```python
from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

# Enable CORS for all routes with Access-Control-Allow-Origin: *

CORS(app)

@app.route('/data')
def data():
    return jsonify(message='Hello from Flask')

```

### Django

Create custom middleware to inject headers into every response:

```python

# myproject/middleware.py

class SimpleCORS:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response["Access-Control-Allow-Origin"] = "*"
        response["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"
        response["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
        return response

```

Add `'myproject.middleware.SimpleCORS'` to the `MIDDLEWARE` list in [`settings.py`](https://github.com/psf/requests/blob/main/settings.py).

### FastAPI

Leverage the built-in `CORSMiddleware` to configure CORS policies declaratively:

```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],          # Or specify ["https://example.com"]

    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/items")
async def read_items():
    return {"msg": "FastAPI CORS enabled"}

```

### Generic WSGI Applications

For frameworks without built-in CORS support, wrap your application with a middleware that modifies the response headers:

```python
def simple_cors_middleware(app):
    def wrapper(environ, start_response):
        def cors_start_response(status, headers, exc_info=None):
            headers.append(("Access-Control-Allow-Origin", "*"))
            headers.append(("Access-Control-Allow-Methods", "GET,POST,OPTIONS"))
            headers.append(("Access-Control-Allow-Headers", "Content-Type,Authorization"))
            return start_response(status, headers, exc_info)
        
        return app(environ, cors_start_response)
    return wrapper

```

Apply this wrapper around any WSGI-compatible application to inject CORS headers into every response.

## Verifying CORS Configuration with the Requests Library

Although `requests` cannot bypass browser CORS restrictions, you can use it to verify that your server sends the correct headers before testing in a browser:

```python
import requests

# Verify pre-flight headers

resp = requests.options('https://api.example.com/data')
print(resp.headers.get('Access-Control-Allow-Origin'))  # Expected: '*'

# Verify actual response headers

resp = requests.get('https://api.example.com/data')
print(resp.headers.get('Access-Control-Allow-Methods'))  # Expected: 'GET,POST,OPTIONS'

```

If these headers appear in the `requests` response but browsers still block your application, ensure your server handles the `OPTIONS` pre-flight method and returns a 200 OK status for those requests.

## Summary

- **CORS is browser-enforced**: The restriction occurs in the browser's security model, not in HTTP client libraries like `requests`.
- **Server-side configuration required**: You must configure `Access-Control-Allow-Origin` and related headers on the API server, not in client code.
- **Key source files**: In `psf/requests`, the [`src/requests/api.py`](https://github.com/psf/requests/blob/main/src/requests/api.py) entry point, [`src/requests/models.py`](https://github.com/psf/requests/blob/main/src/requests/models.py) header handling, and [`src/requests/sessions.py`](https://github.com/psf/requests/blob/main/src/requests/sessions.py) dispatch logic confirm that the library does not process CORS headers.
- **Framework-specific solutions**: Use `flask_cors` for Flask, custom middleware for Django, `CORSMiddleware` for FastAPI, or WSGI wrappers for generic applications.
- **Testing approach**: Use `requests.options()` to verify headers are present before browser testing.

## Frequently Asked Questions

### Why does my Python script work but my browser shows a CORS error?

Python scripts using the `requests` library operate outside the browser's security sandbox and do not enforce CORS policies. Browsers implement Same-Origin Policy protections that block responses lacking `Access-Control-Allow-Origin` headers, which is why the same API call succeeds in Python but fails in JavaScript fetch or XMLHttpRequest.

### Can I add CORS headers to my requests using the requests library to fix the error?

No. Adding headers like `Access-Control-Allow-Origin` to your outgoing request in `requests` (via `headers=` parameter) has no effect because CORS headers must be present in the **server's response**, not the client's request. The browser blocks the response before your JavaScript code can access it if the server fails to send the proper headers.

### What is the minimum CORS configuration needed to allow cross-origin requests?

At minimum, the server must return the `Access-Control-Allow-Origin` header with either a specific origin (e.g., `https://yourdomain.com`) or a wildcard (`*`). For requests with custom headers or non-simple methods (PUT, DELETE), the server must also handle `OPTIONS` pre-flight requests and return `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers`.

### How do I configure CORS headers for specific routes only rather than all API endpoints?

Most frameworks support route-specific CORS configuration. In Flask, use the `@cross_origin()` decorator on specific view functions instead of applying `CORS(app)` globally. In FastAPI, apply the `CORSMiddleware` to specific routers or use the `allow_origins` parameter to restrict which domains can access particular endpoints.