skip to Main Content

I am trying to make a POST call to Django from a React Native Web front end on different subdomains.

I thought I had configured CORS correctly, but that does not seem to be the case.

Here’s what my Django settings.py looks like:

CORS_ALLOW_CREDENTIALS = True

CORS_ALLOW_HEADERS = ['*']

CORS_ALLOWED_ORIGINS = ['https://api.example.com', 'https://example.com', 'https://www.example.com' ]

CSRF_TRUSTED_ORIGINS = [
    'https://api.example.com', 'https://example.com', 'https://www.example.com'
]

ALLOWED_HOSTS = ["0.0.0.0", "api.example.com", "example.com"]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
]

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

What exactly am I doing wrong here? The error I’m getting is this:

Access to XMLHttpRequest at 'https://api.example.com/api/v1/pagescreate/' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

And this is my Django view:

class PageCreateView(generics.CreateAPIView):
    queryset = Page.objects.all()
    serializer_class = PageSerializer

What could be causing this? Am I missing some setting in React? I’m using axios to make the calls, with the only header being "Content-Type": "application/json"

EDIT: Could this be due to some nginx rule on my server? Or maybe my Kubernetes configuration? I am using Docker to set it up the container and can easily link the Dockerfile, or any information from my Kubernetes setup

13

Answers


  1. Are you sure that CORS_ALLOW_HEADERS allows you to set ‘*’?

    Based on here, it looks like it is designed to be extended rather than replaced:
    https://github.com/adamchainz/django-cors-headers/blob/2d22268ff59aa0b79820ea5b8983efd1e514ec4c/README.rst#cors_allow_headers
    This test also led me to think that it is required to be extended rather than replaced
    https://github.com/adamchainz/django-cors-headers/blob/5067faefeb22beffcf1b12dd7ad9d3fb6d4b26e4/src/corsheaders/checks.py#L20-L21

    I would suggest trying that with the default or try extending it from the above link

    I believe that is a library-specific value and not a browser or request CORS value

    edit: added test link to github.com

    Login or Signup to reply.
  2. As explained here, The CORS Access-Control-Allow-Origin line expects in one of these two formats:

    Allow everything: probably not what you want

    Access-Control-Allow-Origin: *
    

    Allow a single specific origin:

    Access-Control-Allow-Origin: [SCHEME]://[HOST]:[PORT_OPTIONAL]
    

    Scheme: AKA protocol, this can be HTTP, HTTPS .
    Host: This has to exactly match the requesting origin, so subdomain.domain.com or domain.com
    Port: [Optional, but important for you] Leaving the port out is the same as putting default port :80 if your scheme is HTTP and :443 if your scheme is HTTPS.

    Also, The server https://example.com which you are making the request to has to implement CORS to grant Script from your website access. Your Script can’t grant itself permission to access another website.

    I used a CORS extension named allow-cors-access-control from chrome web store.

    Or, You can use a change-origin chrome plugin like this:

    Moesif Orign & CORS Changer

    You can make your local dev server (ex: localhost:8080) to appear to be coming from 172.16.1.157:8002 or any other domain.

    Login or Signup to reply.
  3. I had this issue before and I suggest to use:

    CORS_ORIGIN_ALLOW_ALL = True   
    

    that will allow all origins

    with this config ofcourse:

    MIDDLEWARE = [
        ...
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        ...
    ]
    
    INSTALLED_APPS = [
         ...
        'corsheaders',
         ...
    ]
    
    Login or Signup to reply.
  4. Disclaimer: not a django dev.

    But you are using a non-whitelisted value for Content-Type which means your POST request will be "preflighted". Can you confirm the OPTIONS request is properly handled by your API?

    Login or Signup to reply.
  5. If you’re running this in K8s, see if including the following to ALLOWED_HOSTS helps:

    gethostname(), gethostbyname(gethostname())
    
    Login or Signup to reply.
  6. I did something very similar to what you’re doing and this configuration worked for me:

    INSTALLED_APPS = [
        ...
        'corsheaders',
        ...
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',
        '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_ORIGIN_WHITELIST = [
         'https://website.com'
    ]
    
    Login or Signup to reply.
  7. I think, this could be resulted from the sequence of middlewares in the settings. (I am not completely confident though)

    Can you try the following sequence of middleware

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

    and just remove

    CORS_ALLOW_HEADERS = ['*']
    

    from the settings.

    Let me know if this works out

    Login or Signup to reply.
  8. I have had a boatload of CORS issues with Django. Generally, you might try to use:

    CORS_ALLOWED_ORIGINS = ['*']
    
    CSRF_TRUSTED_ORIGINS = ['*']
    

    (Note: This is just boilerplate and you probably don’t want to do it in production; hunting down the actual issue is a necessity in the end)

    to make sure it’s in your Django setup. However, as I have mentioned here: What can cause Chrome to give an net::ERR_FAILED on cached content against a server on localhost?
    There are all sorts of things that can cause CORS errors (sometimes not even registering them as CORS errors) and it can show up coming from all sorts of locations. The real issue is best hunted by digging through your logs.
    (Note: this answer shows how to put your Django logs into files, which you probably should be doing. The standard Django REST-response startup logs will contain useful information)

    Step one is to see if a specific request is hitting your Django logs at all. If it is, your CORS settings within Django are the problem. You can easily tell why it’s getting rejected because Django will have the fully qualified (MYSUBDOMAIN.example.com) domain that it has rejected in the log. This makes changing your Django settings a snap; simply add the rejected domain to your allowed origins.

    Note: If you’re not a BASH / Django pro, going to the log directory (should be referenced in your settings.py) where Django is stuffing its logs and executing ls -alrt will give you the last modified log.

    I have always debugged this problem in Apach2 on Ubuntu, though. So I had a log at /var/log/apache2 that showed me exactly which domain was being rejected and why. (When Apache rejected the request; if you’re putting a web server in front of Django it will also probably have CORS policies and plugins) If you’re using ngnix on docker, the following question (Where are logs of docker nginx conainter stored in host) suggests you use this command line command to get the log files out of docker and see what they’re doing.

    docker inspect --format='{{.LogPath}}' <nginx-containter-id>
    

    I personally will often end up booting a Docker instance from a command line and going to the BASH prompt to debug it. Advice on that is outside the scope of this question.

    Going out a step further, it is possible that this CORS policy problem is even farther out on your network stack. There are times when misconfiguration of security policies, bad redirects, or other infrastructure-related issues are misunderstood by Chrome as CORS issues. A CORS interpretation can even be a browser configuration issue, in some cases. I, on occasion, have booted up a virtual machine to set my security levels in Chrome to the absolute minimum and try it, just to see if CORS was really the issue.

    Sometimes it wasn’t. Sometimes it was that something else – a load balancer, a firewall, a misconfigured AWS security group – was the culprit.

    So, yeah, digging this out can be a full on bug safari rather than simple hunt. But the core thing to check first is whether your Django logs are spitting out anything after each REST request. If they’re not you need to go up the chain because you’re not talking to Django at all.

    Ah, another note: We get CORS errors when Django can’t write to its log files.

    Login or Signup to reply.
  9. Can you try:

    CORS_ORIGIN_WHITELIST = (
    ‘https://example.com’ )

    Login or Signup to reply.
  10. CORS_ALLOW_CREDENTIALS = True makes CORS_ALLOW_HEADERS = ['*'] be translated literally i.e. not as wildcard.

    If you want to add custom headers you need to extend the default list as it’s done in the doc;

    from corsheaders.defaults import default_headers
    
    CORS_ALLOW_HEADERS = list(default_headers) + [
        'my-custom-header',
    ]
    

    As the request has Content-Type of application/json this is not a simple request as per MDN. So this request triggers CORS preflight request which includes Access-Control-Request-Headers request header. This request header elicits Access-Control-Allow-Headers response header.

    Value of this response header can be * to indicate wildcard value in the absence of credentials. But the * is interpreted literally when HTTP cookies or authentication information are present in the request as it’s done here with CORS_ALLOW_CREDENTIALS = True.

    Here in CORS preflight Access-Control-Request-Headers has value of Content-Type but Access-Control-Allow-Headers is a literal * because of CORS_ALLOW_HEADERS = ['*']. So the request is not authorized, that’s why the error No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

    GET works here because it is a "simple request" and doesn’t trigger CORS perflight.

    CORS
    Access-Control-Allow-Headers

    Login or Signup to reply.
  11. I had a similar issue which was solved by shifting corsheaders.middleware.CorsMiddleware above django.middleware.common.CommonMiddleware,in MIDDLEWARE array (settings.py).

    Login or Signup to reply.
  12. I think its possible that you are missing a couple middlewares:

    django.middleware.csrf.CsrfViewMiddleware
    corsheaders.middleware.CorsPostCsrfMiddleware
    

    otherwise I believe there is no problem with your CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS settings

    Login or Signup to reply.
  13. Make sure to restart the server after adding the above configuration and clear the cache and hard reload. It worked for me.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search