244

How can I enable CORS on my Django REST Framework? the reference doesn't help much, it says that I can do by a middleware, but how can I do that?

1
  • Django REST has package django-cors-headers, settings..py can have CORS_ORIGIN_WHITELIST to set Access-Control-Allow-Origin. See: stackoverflow.com/a/49520118/1548275 Commented Feb 21, 2022 at 19:22

15 Answers 15

385

The link you referenced in your question recommends using django-cors-headers, whose documentation says to install the library

python -m pip install django-cors-headers

and then add it to your installed apps:

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

You will also need to add a middleware class to listen in on responses:

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

and specify domains for CORS, e.g.:

CORS_ALLOWED_ORIGINS = [
    'http://localhost:3030',
]

Please browse the configuration section of its documentation, paying particular attention to the various CORS_ORIGIN_ settings. You'll need to set some of those based on your needs.

Sign up to request clarification or add additional context in comments.

14 Comments

do you know any other way to do that, without the need to install a new dependency? I am trying to create a middleware class now
@JulioMarins, why would you write your own version when this is readily available and easily installable, with 12 releases, 21 contributors, over 800 stars and over 100 forks?
You have a point indeed, but since the only need for a simple CORS is a header Access-Control-Allow-Origin: * I don't see why load a whole thing, I will put another way to do this in your answer so both methods can be available. reference: [link(]enable-cors.org/server.html)
@JulioMarins, that would be the sledgehammer approach. If you look at the configuration link I provided you'll see that django-cors-headers is much more flexible than that. If you would prefer to create your own class, be my guest. But I'd be using that library.
@Chris I think you should add CORS_ORIGIN_WHITELIST so that you whitelist the calling host.
|
163
python -m pip install django-cors-headers

and then add it to your installed apps:

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

You will also need to add a middleware class to listen in on responses:

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

CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
    'http://localhost:3030',
] # If this is used, then not need to use `CORS_ALLOW_ALL_ORIGINS = True`
CORS_ALLOWED_ORIGIN_REGEXES = [
    'http://localhost:3030',
]

more details: https://github.com/ottoyiu/django-cors-headers/#configuration

read the official documentation can resolve almost all problem

6 Comments

Adding the four lines you added to @Chris's answer was necessary for this to work for me.
Why is CORS_ORIGIN_ALLOW_ALL = True, but CORS_ORIGIN_WHITELIST is still set? The docs seem to make it seems like this is not required and seems to be confusing for the answer here.
CORS_ORIGIN_ALLOW_ALL If True, the whitelist will not be used and all origins will be accepted.
Also keep in mind 'corsheaders.middleware.CorsMiddleware', needs to be rather at the top of the list, otherwise the connection may be rejected prior to getting to it.
CORS_ORIGIN_ALLOW_ALL = True, this did the trick.
|
25

You can do by using a custom middleware, even though knowing that the best option is using the tested approach of the package django-cors-headers. With that said, here is the solution:

create the following structure and files:

-- myapp/middleware/__init__.py

from corsMiddleware import corsMiddleware

-- myapp/middleware/corsMiddleware.py

class corsMiddleware(object):
    def process_response(self, req, resp):
        resp["Access-Control-Allow-Origin"] = "*"
        return resp

add to settings.py the marked line:

MIDDLEWARE_CLASSES = (
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",

    # Now we add here our custom middleware
     'app_name.middleware.corsMiddleware' <---- this line
)

2 Comments

Thanks Julio! Your middleware code should be updated with @masnun code sample. Also, the import doesn't work for me, importing from . fixes the issue: from . import corsMiddleware
What about this? 'corsheaders.middleware.CorsMiddleware', No need to add?
20

In case anyone is getting back to this question and deciding to write their own middleware, this is a code sample for Django's new style middleware -

class CORSMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response["Access-Control-Allow-Origin"] = "*"

        return response

Comments

17

For Django versions > 1.10, according to the documentation, a custom MIDDLEWARE can be written as a function, let's say in the file: yourproject/middleware.py (as a sibling of settings.py):

def open_access_middleware(get_response):
    def middleware(request):
        response = get_response(request)
        response["Access-Control-Allow-Origin"] = "*"
        response["Access-Control-Allow-Headers"] = "*"
        return response
    return middleware

and finally, add the python path of this function (w.r.t. the root of your project) to the MIDDLEWARE list in your project's settings.py:

MIDDLEWARE = [
  .
  .
  'django.middleware.clickjacking.XFrameOptionsMiddleware',
  'yourproject.middleware.open_access_middleware'
]

Easy peasy!

2 Comments

The approach posted before uses MIDDLEWARE_CLASSES and not MIDDLEWARE. This technique works so the downvote was uncalled for :) @JulioMarins
dude, the solution is the same. You're arguing about implementation on the Django version. Your code is also with wrong indentation on open_access_middleware.
15

Updated 2021 for all those who have the latest version of Django v3.x.x, The steps to allow CORS from any origin are given below.

Step 1: Install required library

pip install django-cors-headers

Step 2: Then add in proper place in your INSTALLED_APPS in settings.py - after the rest_framework and before your application myapp

'rest_framework',
'corsheaders',
'myapp.apps.MyAppConfig',

Step 3: Allow the origins for your api (inside settings.py)

CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',  # for localhost (REACT Default)
'http://192.168.10.45:3000', # for network
)

3 Comments

How will we add some regex to CORS_ORIGIN_WHITELIST ?
@rickster you can use another setting CORS_ALLOWED_ORIGIN_REGEXES
++ This (clearing cache) needs to be done after following these steps :) stackoverflow.com/a/73322250/2233336
12

Updated 2022 and adding a new use case

When your using Axios POST with the option withCredentials: true, there are a few additional options to consider.

I used this specific case for authentification over Basic or/and Session login.

To Avoid error messages as:

Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

And the above mentioned by others. I solved the issue in this way.

[IP addresses are from my local example, have in mind to change it]

setting.py

INSTALLED_APPS = [
    ...
    'rest_framework',
    'corsheaders',
    'rest_framework.authtoken',
    ...
]

ALLOWED_HOSTS = ["localhost","192.168.0.50"]

CORS_ALLOW_CREDENTIALS = True

CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000',  # for localhost (REACT Default)
    'http://192.168.0.50:3000',  # for network 
    'http://localhost:8080',  # for localhost (Developlemt)
    'http://192.168.0.50:8080',  # for network (Development)
)

CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000',  # for localhost (REACT Default)
    'http://192.168.0.50:3000',  # for network 
    'http://localhost:8080',  # for localhost (Developlemt)
    'http://192.168.0.50:8080',  # for network (Development)
]

MIDDLEWARE = [
...
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsMiddleware',
...

]

On the browser, the Axios request headers must be send and on the server site the headers must be permitted. If not, the error message will be.

Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.

Up to this moment play with the headers. You can add more headers if you need them, like:

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

Cheers :)

Comments

9

Below are the working steps without the need for any external modules:

Step 1: Create a module in your app.

E.g, lets assume we have an app called user_registration_app. Explore user_registration_app and create a new file.

Lets call this as custom_cors_middleware.py

Paste the below Class definition:

class CustomCorsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)
        response["Access-Control-Allow-Origin"] = "*"
        response["Access-Control-Allow-Headers"] = "*"

        # Code to be executed for each request/response after
        # the view is called.

        return response

Step 2: Register a middleware

In your projects settings.py file, add this line

'user_registration_app.custom_cors_middleware.CustomCorsMiddleware'

E.g:

  MIDDLEWARE = [
        'user_registration_app.custom_cors_middleware.CustomCorsMiddleware', # ADD THIS LINE BEFORE CommonMiddleware
         ...
        'django.middleware.common.CommonMiddleware',

    ]

Remember to replace user_registration_app with the name of your app where you have created your custom_cors_middleware.py module.

You can now verify it will add the required response headers to all the views in the project!

1 Comment

Thank you! I was missing the Access-Control-Allow-Headers header.
5

Well, I don't know guys but:

using here python 3.6 and django 2.2

Renaming MIDDLEWARE_CLASSES to MIDDLEWARE in settings.py worked.

Comments

5

first install django package

pip install django-cors-headers

and add to apps in settings file

INSTALLED_APPS = (
...
'corsheaders',
...
)

and then add cors middle ware to setting file

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

and finally add cross orgin whitelist

#CORS_ORIGIN_ALLOW_ALL = True
#CORS_ALLOW_CREDENTIALS = True
#CORS_ALLOW_HEADERS = ['*']
CORS_ORIGIN_WHITELIST = ('http://localhost:5000',)

that will solve cors error easily. happy coding

Comments

2

After trying every suggested solution and nothing seemed to work. I finally fixed the issue after much frustration by clearing my browser cache...

Then the accepted answer works by using django-cors-headers.

Hope this helps someone else!

Shell command to clear the cache -

find . -name '*.pyc' -type f -delete && find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)" | xargs rm -rf

Comments

2

So considering that I had just solved this problem myself, let's go through the different ways CORS can go wrong.

Preliminary

In case anybody needs a refresher, CORS stands for Cross Origin Resource Sharing, and it's triggered whenever browser JS makes an HTTP(S) request to a different website. It puts no such restrictions outside the browser.

A CORS-enabled backend will send a number of headers in the response back to the frontend, and one of them is Access-Control-Allow-Origin. The value of this header is going to be the URL (minus the path) of the frontend making the query. Example: https://example.com, http://localhost:3000 etc. It is even required when you're using localhost, and it works because the URL is not actually being called by the backend. It's just a string that it compares to a list of allowed origins, specified in the Django middleware.

An Access-Control-Allow-Origin will only be sent in the response when an Origin header is included in the request. All browsers send this header and for security reasons it cannot be changed. It can only be the origin specified in the browser URL. You could try making a request with cURL and send a different value using -IH <origin> just to see what what the response is like, but that's out of scope here.

This will only be dealing with how to get GET requests working. POST and PUT requests also need the CSRF settings that are explained in the other answers.

Make sure it's actually a problem with CORS

Sometimes you might have .pyc files cached or HTTP responses cached inside your browser that make you think that you have a problem with CORS, but it has already been fixed. To make sure this is not the case:

  1. Clear your pycache using the command in this answer.
  2. Open your browser settings and go to the Clear Browsing Data section, and clear cached images and files. This also fixes a lot of weird errors where you get an old kind of response from the backend but just to your browser while everything else works fine.

Getting rid of duplicate CORS entries

If you are running a production Django server behind a reverse proxy such as Nginx or Apache, adding an Access-Control-Allow-Origin header might actually cause the request to fail CORS. This happens because both Django, through a middleware, and the reverse proxy are both adding an Access-Control-Allow-Origin to the response, but the HTTP response the browser expects is only supposed to receive this header once. If you see errors like this in the Developer Tools console:

Access to XMLHttpRequest at 'https://example.com/api' from origin 'http://localhost:3000' has been blocked by CORS policy: 
The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:3000, *', but only one is allowed.

then that is the reason why. This error can occur even if you allow all origins using *.

For this reason I do not recommend adding CORS headers in Nginx or the other reverse proxy, because Django will already add those.

Making sure Django has CORS

You need to follow the steps in this answer (currently, it is the accepted answer), which is to install django-cors-headers using Pip, then open settings.py which is to add corsheaders to the INSTALLED_APPS, and corsheaders.middleware.CorsMiddleware to the MIDDLEWARE. You don't need to add the CommonMiddleware line because it is already present in the file, just make sure it is below CorsMiddleware.

Then add your frontend URLs without paths to CORS_ALLOWED_ORIGINS or just set CORS_ALLOW_ALL_ORIGNIS to True (not recommended) and restart Django or your WSGI runtime.

If you are still experiencing CORS errors

If for some reason the browser is not seeing Access-Control-Allow-Origin response headers and is blocking your requests, try the following:

  • Clear your browser cache - it is usually the culprit (for me it was).
  • Make sure you don't have other middleware or Nginx settings with conflicting CORS settings.
  • Make sure the backend endpoint is working properly and not throwing 5xx errors due to exceptions. Especially if you did not putCorsMiddleware at the top, Django might return the error response without any CORS headers. In general, you should ensure your backend is bug-free before trying to fix CORS errors - it will save you a lot of time.

Comments

0

Django=2.2.12 django-cors-headers=3.2.1 djangorestframework=3.11.0

Follow the official instruction doesn't work

Finally use the old way to figure it out.

ADD:

# proj/middlewares.py
from rest_framework.authentication import SessionAuthentication


class CsrfExemptSessionAuthentication(SessionAuthentication):

    def enforce_csrf(self, request):
        return  # To not perform the csrf check previously happening

#proj/settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'proj.middlewares.CsrfExemptSessionAuthentication',
    ),
}

Comments

0

It worked for me when placing corsheaders.middleware.CorsMiddleware as the last bit of middleware

Comments

0
  1. First Install django-cors-headers package, For that add this command to command prompt or power shell etc.

pip install django-cors-headers or python -m pip install django-cors-headers

  1. In settings.py file, Add 'corsheaders' in INSTALLED_APPS
INSTALLED_APPS = [
    ...,
    'corsheaders',
    ...,
]
  1. In settings.py file, Add 'corsheaders.middleware.CorsMiddleware' in MIDDLEWARE
MIDDLEWARE = [
...,
'corsheaders.middleware.CorsMiddleware',
...,
]
  1. In settings.py file, Add below content at the End of the file
CORS_ALLOWED_ORIGINS = [
    "http://localhost:5173",  # Add your frontend URL here
]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.