Skip to content

CORS in Django — Configuring Cross-Origin Requests with django-cors-headers

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about CORS in Django. We cover key concepts, practical examples, and best practices to help you master this topic.

Django provides CORS support through the django-cors-headers package, which adds middleware for handling CORS headers, preflight requests, and configurable origin, method, and header whitelists.

What You'll Learn

  • Installing and configuring django-cors-headers
  • Setting up CORS middleware in settings.py
  • Configuring allowed origins, methods, and headers

Why It Matters

Django powers many content-heavy and enterprise APIs. Proper CORS configuration enables secure cross-origin access for React, Vue, and Angular frontends. DodaTech's content management API uses Django with django-cors-headers.

flowchart LR
    A["Django Settings"] --> B["INSTALLED_APPS"]
    A --> C["MIDDLEWARE"]
    A --> D["CORS_ALLOWED_ORIGINS"]
    B --> E["corsheaders"]
    C --> F["CorsMiddleware"]
    D --> G["Origin whitelist"]

Code Examples

# Django settings.py CORS configuration
INSTALLED_APPS = [
    # ...
    'corsheaders',
    # ...
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # ...
]

# Configure allowed origins
CORS_ALLOWED_ORIGINS = [
    "https://app.example.com",
    "https://admin.example.com",
    "https://dashboard.example.com",
]

# Or allow all origins (development only)
CORS_ALLOW_ALL_ORIGINS = False  # Never True in production

# Allow credentials
CORS_ALLOW_CREDENTIALS = True

# Configure allowed methods and headers
CORS_ALLOW_METHODS = [
    'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'
]

CORS_ALLOW_HEADERS = [
    'accept', 'authorization', 'content-type',
    'origin', 'x-csrftoken', 'x-requested-with',
]

# Expose custom headers to JavaScript
CORS_EXPOSE_HEADERS = [
    'x-ratelimit-remaining', 'x-request-id'
]

# Preflight cache duration
CORS_PREFLIGHT_MAX_AGE = 86400  # 24 hours
# Per-view CORS configuration
from corsheaders.decorators import cors_allow_all
from django.http import JsonResponse

@cors_allow_all()
def public_view(request):
    return JsonResponse({"data": "public"})

# Or with specific origins
from corsheaders.decorators import cors_allow_origin

@cors_allow_origin("https://admin.example.com")
def admin_view(request):
    return JsonResponse({"data": "admin"})
# Regex-based origin matching
CORS_ALLOWED_ORIGIN_REGEXES = [
    r"^https://[\w-]+\.example\.com$",
    r"^https://(www\.)?app\.example\.com$",
]
# Test Django CORS configuration
curl -I -H "Origin: https://app.example.com" \
  http://localhost:8000/api/data | grep -i "access-control"

curl -I -H "Origin: https://evil.com" \
  http://localhost:8000/api/data | grep -i "access-control"

Common Mistakes

1. Not Placing CorsMiddleware Before CommonMiddleware

CorsMiddleware must be placed before CommonMiddleware in the MIDDLEWARE list.

2. Using CORS_ALLOW_ALL_ORIGINS in Production

This allows any website to read API responses. Always use CORS_ALLOWED_ORIGINS.

3. Forgetting CSRF Token Exemption for OPTIONS

Django CSRF middleware blocks OPTIONS requests. Add corsheaders to CSRF_TRUSTED_ORIGINS.

Cross-origin requests with credentials need CSRF_COOKIE_SAMESITE = 'None' and CSRF_COOKIE_SECURE = True.

5. Using Origin Without Trailing Slashes

CORS_ALLOWED_ORIGINS entries should not have trailing slashes.

Practice Questions

  1. What package provides CORS support in Django?
  2. Where should CorsMiddleware be placed in the MIDDLEWARE list?
  3. How do you allow credentials in Django CORS?
  4. What setting allows all origins (development only)?
  5. How do you configure regex-based origin matching?

Answers:

  1. django-cors-headers.
  2. Before CommonMiddleware, typically at the top of the MIDDLEWARE list.
  3. Set CORS_ALLOW_CREDENTIALS = True.
  4. CORS_ALLOW_ALL_ORIGINS = True.
  5. Use CORS_ALLOWED_ORIGIN_REGEXES with a list of regex patterns.

Challenge: Build a Django REST Framework API with tiered CORS configuration: public endpoints with open CORS, authenticated endpoints with restricted origins, and admin endpoints with strict origin and credential requirements.

FAQ

Does django-cors-headers handle OPTIONS preflight automatically?

Yes. CorsMiddleware intercepts OPTIONS requests and returns the appropriate CORS headers based on your configuration. No custom OPTIONS handlers needed.

How does Django CORS work with Django REST Framework?

DRF views go through the same middleware stack. The CorsMiddleware handles CORS at the middleware level, which applies to all views including DRF viewsets and APIViews.

Can I configure CORS per-view in Django?

Yes. Use the @cors_allow_all() or @cors_allow_origin() decorators for per-view CORS configuration, overriding the global settings.

How do I debug CORS issues in Django?

Enable Django's CORS logging: add LOGGING configuration for 'corsheaders' logger at DEBUG level. Check request and response headers with curl.

Does Django CORS work with Django Channels (WebSocket)?

Django CORS middleware works for HTTP requests only. WebSocket connections in Django Channels have different CORS considerations handled on the ASGI level.

Mini Project

Build a Django REST API with three tiers of CORS configuration. Implement django-cors-headers for public, partner, and admin endpoints. Add Django REST Framework authentication, CSRF protection with cross-origin cookies, and automated tests using pytest that validate CORS behavior for each endpoint tier.

What's Next

Now explore framework-specific CORS for Express, FastAPI, and other platforms.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro