-1

I have a Django REST backend (currently running as http://localhost:8000) and a React front-end (on http://localhost:3000) and I am struggling having the cross origin certification to work.

Most of the solutions I read here (see for example 1 or 2) were to do CORS_ORIGIN_ALLOW_ALL = True and CORS_ALLOWED_ORIGINS = [*] but it is not something I wish to do. I want it to be safe for production and understand how to setup the csrf authentification properly.

Error message:

In Django console I see:

[24/Aug/2021 13:48:18] "OPTIONS /calc/ HTTP/1.1" 200 0
Forbidden (CSRF cookie not set.): /calc/

In the browser I have:

Failed to load resource: the server responded with a status of 403 (Forbidden)

Files:

Django REST API:

I have install django-cors-headers.

  • settings.py:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'maapi', # This is my app
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware', # Cors header are here
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

[...]

CORS_ORIGIN_ALLOW_ALL = False

CORS_ALLOWED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]

CORS_ALLOW_CREDENTIALS = True

CSRF_TRUSTED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]
  • maapi/views.py:
class Calc(View):
    """
    Run a static simulation.
    """

    def post(self, request, *args, **kwargs):
        rjson = json.loads(request.body)
        try:
            # do things
            return JsonResponse(results)
        except Exception as e:
            return e, 500
  • urls.py:
from maapi import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('calc/', views.Calc.as_view(), name='calc'),
    # path('calc/', ensure_csrf_cookie(views.Calc.as_view()), name='calc'), # I tried this one too without more success
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
]

React Frontend:

I used the tutorial here.

  • CrsfToken.js:
import React from 'react';

function getCookie(name) {
    let cookieValue = null;

    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();

            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));

                break;
            }
        }
    }

    return cookieValue;
}

const csrftoken = getCookie('csrftoken');

const FormCsrfToken = () => {
    return (
        <input name="csrfmiddlewaretoken" value={csrftoken} type="hidden" />
    );
};

export default FormCsrfToken;
export { csrftoken }
  • App.js:
import { csrftoken } from './CsrfToken';

function App() {

  [...]

  const getdata = () => {
    setFetching(true);
    const bod = {
      // Things
    };
    fetch("http://localhost:8000/calc/", {
      method: "POST",
      credentials: 'include',
      mode: 'cors',
      headers: {
        'Accept': 'application/json',
        "Content-Type": "application/json",
        'X-CSRFToken': csrftoken,
      },
      body: JSON.stringify(bod),
    })
      .then((response) => {
        return response.json();
      })
      .then((d) => {
        // Do things
      })
      .catch((object) => {
        setFetching(false);
        openNotification();
      });
  };

Can you spot what is missing?

Romn
  • 174
  • 2
  • 14

1 Answers1

0

I have fixed it:

Just change your CSRF_TRUSTED_ORIGINS to this:

 CSRF_TRUSTED_ORIGINS = [
    "127.0.0.1:3000",
    "localhost:3000",
]

And one more thing, don't send the csrftoken with the request. You don't need it. You can remove it.

Pranava Mohan
  • 533
  • 2
  • 8
  • 18
  • Thank you, I have try but it doesn't change anything and I still have the same issue `Forbidden (CSRF cookie not set.): /calc/` (with or without the `csrftoken` on the frontend). – Romn Aug 25 '21 at 03:23
  • try removing, `credentials:'include'` from your fetch request and also remove `CORS_ALLOW_CREDENTIALS` from your settings.py – Pranava Mohan Aug 25 '21 at 03:56
  • Thank you but still the same error `Forbidden (CSRF cookie not set.): /calc/` when removing both the credentials from the request and `CORS_ALLOW_CREDENTIALS`. – Romn Aug 30 '21 at 05:44