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
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
As explained here, The CORS
Access-Control-Allow-Origin
line expects in one of these two formats:Allow everything: probably not what you want
Allow a single specific origin:
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 from172.16.1.157:8002
or any other domain.I had this issue before and I suggest to use:
that will allow all origins
with this config ofcourse:
Disclaimer: not a django dev.
But you are using a non-whitelisted value for
Content-Type
which means yourPOST
request will be "preflighted". Can you confirm theOPTIONS
request is properly handled by your API?If you’re running this in K8s, see if including the following to ALLOWED_HOSTS helps:
I did something very similar to what you’re doing and this configuration worked for me:
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
and just remove
from the settings.
Let me know if this works out
I have had a boatload of CORS issues with Django. Generally, you might try to use:
(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.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.
Can you try:
CORS_ALLOW_CREDENTIALS = True
makesCORS_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;
As the request has
Content-Type
ofapplication/json
this is not a simple request as per MDN. So this request triggers CORS preflight request which includesAccess-Control-Request-Headers
request header. This request header elicitsAccess-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 withCORS_ALLOW_CREDENTIALS = True
.Here in CORS preflight
Access-Control-Request-Headers
has value ofContent-Type
butAccess-Control-Allow-Headers
is a literal*
because ofCORS_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
I had a similar issue which was solved by shifting
corsheaders.middleware.CorsMiddleware
abovedjango.middleware.common.CommonMiddleware
,inMIDDLEWARE
array (settings.py).I think its possible that you are missing a couple middlewares:
otherwise I believe there is no problem with your CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS settings
Make sure to restart the server after adding the above configuration and clear the cache and hard reload. It worked for me.