Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS issue with Django and React hosted on same server

I am having a CORS issue with my Django Rest Framework and React app on the same server. I am running Vagrant with an Ubuntu 18 box and NGINX installed (I am assuming this issue will translate to DigitalOcean) I apologize ahead of time if I am providing too much information. DRF is using Supervisor and Gunicorn is on port 8000. I created my React app using create-react-app. I then used npm run build to create the static files.

NGINX Setup:

React Conf

server {
    listen 8080;
    server_name sandbox.dev;

    root /var/sites/sandbox/frontend/build;
    index index.html;
    client_max_body_size 4G;
    location / {
        try_files $uri $uri/ /index.html;
    }

Django Conf

upstream sandbox_server {
    server unix:/var/tmp/gunicorn_sanbox.sock fail_timeout=0;
}
server {
    listen 8000;
    server_name api.sandbox.dev;
    ...
    location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    if (!-f $request_filename) {
        proxy_pass http://sandbox_server;
        break;
    }

Django Setup:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'corsheaders',
    'myapp',
]
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

I have tried the following with no luck

CORS_ORIGIN_ALLOW_ALL = True

and

CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = ('192.168.19.76:8080','localhost:8080',)

React App.js

...
fetch("http://localhost:8000/api/v1/token-auth/", {
    method: 'POST',
    headers: {
       'Content-Type': 'application/json',
    },
    body: JSON.stringify({"email":"[email protected]", "password":"testuser"}),
})

So to state the obvious CORS is correct because the Origin is localhost:8080 which is a different port so it sees it as cross origin. I have tried the different settings with cors origin allow, but it is still the same issue every time. Obviously I am doing something wrong, but I can't see it.

My thoughts are

Option 1

proxy pass using the django nginx conf file and do away with the react nginx conf file, but I don't know what affect that might cause in production or if this is a good idea. Is there a better way?

location /api {
    proxy_set_header X-Forwarded_for $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://sandbox_server;

So finalize my thoughts and my question. After trying the different Django options for CORS I am still getting the CORS error. Why, and is it my NGINX conf files causing it or something else? Will I expect to see this in DigitalOcean?

UPDATE 1

I forgot to add the error. Here is the CORS error

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/v1/token-auth/. (Reason: CORS request did not succeed).

For those wanting to know the output from the network tab

Host    localhost:8000
Origin  http://192.168.19.76:8080
Pragma  no-cache
Referer http://192.168.19.76:8080/

UPDATE 2 I did test using curl, and everything returned as expected so I know DRF is working corrently.

curl --data "[email protected]&password=testuser" http://localhost:8000/api/v1/token-auth/

FINAL UPDATE

Thanks to paulsm4 for all the help and just plain awesomeness.

So, I did abandon django-cors-headers and rolled my own. To answer paulsm4's question, I do not have add_header 'Access-Control-Allow-Origin' '*'; in the NGINX file although I did think about letting NGINX handle CORS vs Django, but never went that far. @paulsm4, this is the proxy_pass I was talking about. The key was adding this block of code to NGINX for the react portion in conjunction with my middleware.

    location /api {
        proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://sandbox_server;

The above code by itself worked, but it did not allow me to whitelist any incoming URLs. Creating my own middleware allowed me to whitelist. I have no idea why django-cors-headers or even django-cors-middleware did not work for me. What was strange was that fetch never made it far enough with those two packages to get response headers and an error of any sorts, other than the CORS error I was asking about. With the middleware I wrote, fetch was able to fully make the call, and return some response headers whether it succeeded or failed.

For future reference, I might revisit NGINX and allowing it to handle CORS. Here is a good link CORS on NGINX

NOTE

To clarify; the only middleware installed besides what Django already includes is the cors middleware. Both Django and React reside on the same server, but with different ports.

  1. api.sandbox.com:8000 is the Django Rest Framework
  2. app.sandbox.com:8080 is the React static files
  3. Django 2.0.2
  4. Python 3.6
  5. django-cors-headers 2.4.0
  6. Vagrant/VirtualBox Ubuntu 18.04
  7. NGINX

Django settings.py

INSTALLED_APPS = [
    ...
    # Third Party
    'rest_framework',
    'corsheaders',
    # My Apps
    'account',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
    'django.middleware.csrf.CsrfViewMiddleware',
    'corsheaders.middleware.CorsPostCsrfMiddleware',
    ...
]
CORS_ORIGIN_WHITELIST = (
    'null',
    '192.168.19.76:8080',
    'localhost:8080',
    'app.sandbox.com:8080'
)

React App.js

    fetch("http://localhost:8000/api/v1/token-auth/", {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            "email": "[email protected]", 
            "password": "testuser"
       }),
    })

So I am at wits end here. It is either django-cors-headers that is not working or it could possibly be NGINX.

like image 254
vhalik Avatar asked Jan 25 '19 19:01

vhalik


1 Answers

We've been exchanging comments; here's my current understanding:

PROBLEM: You have have a Django back-end API (on port 8080) and a React Front end (on port 8000). Both are currently running on localhost, but will ultimately reside on DigitalOcean. The React client is getting Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/api/v1/token-auth/. (Reason: CORS request did not succeed).

You need to configure CORS.

The request headers in the HTTP traffic you've captured clearly shows this isn't happening yet.

Some relevant links include:

  • django-cors-headers not work

  • Handling CORS in Django REST Framework

  • Djgano REST Framework: CORS

SUGGESTED NEXT STEP:

If you haven't already, please install and configure django-cors-headers

like image 69
paulsm4 Avatar answered Sep 28 '22 21:09

paulsm4