Search code examples
pythondjangonext.jsfetch-apidjango-cors-headers

django-cors-headers does not allow a request from an allowed origin


The problem that I am facing is that I cannot fetch an existing user from my NextJS frontend. The backend framework that I use is Django (along with the django-cors-headers package). django-cors-headers does not allow a certain HTTP request, while it should.

My next.config.js contains a rewrite, so that I can access my backend.

async redirects() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://localhost:8000/:path*/',
        permanent: true,
      },
    ]
  },

And my django-cors-headers settings look like this:

# CORS

CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000',
]

CORS_ALLOWED_ORIGINS = [
    'http://localhost:3000',
    'http://localhost:8000',
    'http://127.0.0.1:3000',
    'http://127.0.0.1:8000',
]

CORS_ALLOW_ALL_ORIGINS = True

The request that fails attempts to fetch a user with an ID of 1. This user exists and therefore, this request should succeed.

fetch(`/api/users/${String(userId)}/`, {
    mode: 'cors',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
    },
  })

However, the only thing that I get back from the request is an error message about CORS.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8000/users/1.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Status code: 301.

It looks like my django-cors-headers setup is wrong. But I am allowed to obtain my JWT tokens. The following request succeeds.

fetch('/api/token', {
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email: mail,
      password,
    }),
  })

Solution

  • I tried pretty much everything EXCEPT for double checking the load order of my middleware... I fixed my issue by going from the following load order

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

    ... to

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

    I knew that it had to be something simple, but now I just feel like a grand idiot...