CORS
Django
REST Framework
Django REST Framework
web development

How can I enable CORS on Django REST Framework

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Cross-Origin Resource Sharing (CORS) controls whether a browser allows JavaScript on one domain to make requests to a different domain. When your Django REST Framework API runs on api.example.com and your frontend runs on app.example.com, the browser blocks requests unless the API sends the correct CORS headers. The django-cors-headers package is the standard solution.

Install and Configure django-cors-headers

Install the package and add it to your Django settings.

bash
pip install django-cors-headers
python
1# settings.py
2
3INSTALLED_APPS = [
4    # ...
5    "corsheaders",
6    "rest_framework",
7    # ...
8]
9
10MIDDLEWARE = [
11    "corsheaders.middleware.CorsMiddleware",  # Must be before CommonMiddleware
12    "django.middleware.common.CommonMiddleware",
13    # ... other middleware
14]

The CorsMiddleware must appear before any middleware that generates responses (especially CommonMiddleware) so it can add headers to all responses including error pages.

Whitelist the exact origins that should access your API.

python
1# settings.py
2
3CORS_ALLOWED_ORIGINS = [
4    "https://app.example.com",
5    "https://admin.example.com",
6]

This is the safest configuration for production. Only listed origins receive Access-Control-Allow-Origin headers.

Allow All Origins (Development Only)

For local development where frontend and API run on different ports:

python
# settings.py

CORS_ALLOW_ALL_ORIGINS = True  # Do NOT use in production

This sends Access-Control-Allow-Origin: * for every request. Never deploy this to production — it allows any website to make requests to your API.

Allow Origins by Regex Pattern

When you need to support multiple subdomains or dynamic environments:

python
1# settings.py
2
3CORS_ALLOWED_ORIGIN_REGEXES = [
4    r"^https://.*\.example\.com$",
5    r"^https://deploy-preview-\d+\.netlify\.app$",
6]

Regex patterns are checked when the origin does not match CORS_ALLOWED_ORIGINS exactly.

Configure Allowed Methods and Headers

By default, django-cors-headers allows standard methods and headers. Customize when your API uses non-standard headers:

python
1# settings.py
2
3CORS_ALLOW_METHODS = [
4    "DELETE",
5    "GET",
6    "OPTIONS",
7    "PATCH",
8    "POST",
9    "PUT",
10]
11
12CORS_ALLOW_HEADERS = [
13    "accept",
14    "authorization",
15    "content-type",
16    "x-csrftoken",
17    "x-requested-with",
18    "x-custom-header",  # Add any custom headers your frontend sends
19]

Enable Credentials (Cookies and Auth Headers)

If your API uses session cookies or HTTP authentication:

python
1# settings.py
2
3CORS_ALLOW_CREDENTIALS = True
4
5# When using credentials, you CANNOT use CORS_ALLOW_ALL_ORIGINS
6# You must specify exact origins
7CORS_ALLOWED_ORIGINS = [
8    "https://app.example.com",
9]

The browser refuses to send credentials to a * origin. You must list specific allowed origins when credentials are enabled.

Expose Custom Response Headers

If your API returns custom headers that the frontend needs to read:

python
1# settings.py
2
3CORS_EXPOSE_HEADERS = [
4    "X-Request-Id",
5    "X-Total-Count",
6]

Without this, the browser hides non-standard response headers from JavaScript.

Complete Production Example

python
1# settings.py
2
3INSTALLED_APPS = [
4    "corsheaders",
5    "rest_framework",
6    # ...
7]
8
9MIDDLEWARE = [
10    "corsheaders.middleware.CorsMiddleware",
11    "django.middleware.common.CommonMiddleware",
12    "django.middleware.security.SecurityMiddleware",
13    # ...
14]
15
16CORS_ALLOWED_ORIGINS = [
17    "https://app.example.com",
18    "https://admin.example.com",
19]
20
21CORS_ALLOW_CREDENTIALS = True
22
23CORS_ALLOW_HEADERS = [
24    "accept",
25    "authorization",
26    "content-type",
27    "x-csrftoken",
28    "x-requested-with",
29]
30
31CORS_EXPOSE_HEADERS = [
32    "X-Request-Id",
33]

Common Pitfalls

  • Placing CorsMiddleware after CommonMiddleware — the CORS headers never get added because responses are already generated.
  • Using CORS_ALLOW_ALL_ORIGINS = True with CORS_ALLOW_CREDENTIALS = True — browsers reject this combination. Use explicit origin lists with credentials.
  • Forgetting to add corsheaders to INSTALLED_APPS — the middleware loads but configuration settings are ignored.
  • Confusing CORS_ALLOWED_ORIGINS (list of strings) with CORS_ALLOWED_ORIGIN_REGEXES (list of regex patterns) and mixing the formats.
  • Not handling preflight OPTIONS requests — django-cors-headers handles these automatically, but custom middleware that short-circuits responses can block them.

Summary

  • Install django-cors-headers and add CorsMiddleware before CommonMiddleware.
  • Use CORS_ALLOWED_ORIGINS with explicit origin URLs for production.
  • Use CORS_ALLOW_ALL_ORIGINS = True only during local development.
  • Set CORS_ALLOW_CREDENTIALS = True with specific origins when using cookies or auth headers.
  • Add custom headers to CORS_ALLOW_HEADERS and CORS_EXPOSE_HEADERS as needed.

Course illustration
Course illustration

All Rights Reserved.