CORS Handling Middleware

A snippet showing how to allow CORS with custom middleware.


# middleware.py

from django.http import HttpResponse
from django.conf import settings

class CORSMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.allowed_origins = set(getattr(settings, 'CORS_ALLOWED_ORIGINS', []))
        self.allow_all = getattr(settings, 'CORS_ALLOW_ALL_ORIGINS', False)
        self.allow_headers = getattr(settings, 'CORS_ALLOW_HEADERS', ['Content-Type', 'Authorization'])
        self.allow_methods = getattr(settings, 'CORS_ALLOW_METHODS', ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'])
        self.allow_credentials = getattr(settings, 'CORS_ALLOW_CREDENTIALS', False)
        self.max_age = getattr(settings, 'CORS_PREFLIGHT_MAX_AGE', 86400)  # 1 day

    def __call__(self, request):
        # Handle preflight
        if request.method == 'OPTIONS' and 'HTTP_ORIGIN' in request.META:
            origin = request.META['HTTP_ORIGIN']
            if self._origin_allowed(origin):
                resp = HttpResponse(status=204)
                self._set_cors_headers(resp, origin, is_preflight=True, request=request)
                return resp
        # Normal request flow
        response = self.get_response(request)
        origin = request.META.get('HTTP_ORIGIN')
        if origin and self._origin_allowed(origin):
            self._set_cors_headers(response, origin, is_preflight=False, request=request)
        return response

    def _origin_allowed(self, origin):
        return self.allow_all or origin in self.allowed_origins

    def _set_cors_headers(self, response, origin, is_preflight, request):
        response['Access-Control-Allow-Origin'] = '*' if self.allow_all and not self.allow_credentials else origin
        if self.allow_credentials:
            response['Access-Control-Allow-Credentials'] = 'true'
        if is_preflight:
            req_headers = request.headers.get('Access-Control-Request-Headers', '')
            response['Access-Control-Allow-Headers'] = ', '.join(self.allow_headers) if not req_headers else req_headers
            response['Access-Control-Allow-Methods'] = ', '.join(self.allow_methods)
            response['Access-Control-Max-Age'] = str(self.max_age)
  

# settings.py

MIDDLEWARE = [
    # ...
    'your_app.middleware.CORSMiddleware',
]

# Allow specific origins (preferred in production)
CORS_ALLOWED_ORIGINS = [
    'https://example.com',
    'https://admin.example.com',
]

# Optionally allow all (avoid with credentials)
CORS_ALLOW_ALL_ORIGINS = False

# Fine-tune allowed headers/methods
CORS_ALLOW_HEADERS = ['Content-Type', 'Authorization']
CORS_ALLOW_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']

# Cookies / Authorization headers across origins
CORS_ALLOW_CREDENTIALS = False  # set True only if you trust the origin

# Cache preflight results
CORS_PREFLIGHT_MAX_AGE = 86400
  

# Example curl tests

# Preflight request
$ curl -i -X OPTIONS http://localhost:8000/api/items/   -H "Origin: https://example.com"   -H "Access-Control-Request-Method: GET"

# Actual request
$ curl -i http://localhost:8000/api/items/ -H "Origin: https://example.com"
  
Explanation:
  • The middleware adds CORS headers to both preflight (OPTIONS) and actual responses when the origin is allowed.
  • Prefer whitelisting CORS_ALLOWED_ORIGINS. Use CORS_ALLOW_ALL_ORIGINS only in dev or public APIs without credentials.
  • If you need cookies/Authorization across origins, enable CORS_ALLOW_CREDENTIALS and avoid * for Allow-Origin.
  • For production, consider the maintained package django-cors-headers for advanced rules & security hardening.
  • Category Middleware
  • Total Views 420
  • Last Modified 28 March, 2026
  • Tags #middleware #cors #api #headers
Never miss a story on Django.wiki

Subscribe for fresh tutorials, snippets, and updates.

By subscribing you agree to our Privacy Policy.