Rodrigo Reyes
Rodrigo Reyes

Reputation: 326

Why I can't set X-CSRFToken in request to Django REST API?

well I've been trying to solve this issue for two days and I can't figure it where is the problem, your sugestions with tests to try, readings or a solution would be appreciated, here goes the explanation:

I'm making chrome extension to add some data to Django REST API, it works fine when @csrf_exempt decorator is added to the view when POST request is made from chrome extension, and when POSTrequests are made from the same domain even when I delete @csrf_exemptdecorator (local server), but when I try to make a POST request from my extension I get this server error: Forbidden (CSRF cookie not set.) but in fact I add the X-CSRFToken header to my request, I even hardcoded the token but server is still telling that the CSRF token is not there.

I'm already using django-cors-headers-multi 1.2.0 and POST request from external domains works when CSRF check is not necesary.

I check the following links:

Django X-CSRFToken have been set but still get 403 forbidden --> but I'm not making an XMLrequest, should I try to make one? (I've never made one and I'm trying to save time so I don't want to learn that right now)

https://pypi.org/project/django-cors-headers-multi/ --> I already added CORS_ALLOW_CREDENTIALS = False because before I obtain the follow message on chrome console: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'

Here is the code I think is relevant to solve this: FRONTEND (EXTENSON CODE)

    function makeRequest(value, csrf) {
  // Send data to server

  url = 'http://127.0.0.1:8000/smoke/add/';

  let request = new Request(url, {
    method: 'POST',
    credentials: 'include',
    headers: myHeaders,
    headers: {
      'Content-Type': 'text/plain',
      'X-CSRFToken': 'hardCodedToken',
    },
    body: JSON.stringify({
      info: value,
    }),
  });
  
  return request;
}

chrome.storage.sync.get('token', (csrf) => {
        request = makeRequest(contactData, csrf);
        console.log(request);
        fetch(request) // Error is here
          .then((response) => response.json())
          .then((data) => {
            if (data.error !== undefined) {
              alert('Este nombre de contacto ya existe');
            } else {
              console.log(data.contact);
            }
          });
      });

This is the console print I obtain: enter image description here enter image description here

SERVER CODE:

@ensure_csrf_cookie
def add_lead(request):
added = False
if request.method == 'POST':
    try:
        data = json.loads(request.body)
        
        #creates lead
        lead = Lead.objects.create(name=data['info']['name'], nick=data['info']['nick'])
        lead.save()

        #creates contact from lead
        WA_phone = None
        try:
            WA_phone = data['info']['WApn']
        except:
            pass

        phone = LeadPhone.objects.create(lead=lead, phone=data['info']['phone'], whats_app=WA_phone)

        phone.save()

        mail = LeadMail.objects.create(lead=lead, mail=data['info']['mail'])
        mail.save()

        field = LeadField.objects.create(lead=lead, field=data['info']['field'])
        field.save()

        added = True # shows status to JS fetch function

        contact = {
            'lead': lead.id,
            'name': lead.name,
            'nick': lead.nick,
            'phone': phone.phone,
            'mail': mail.mail,
            'field': field.field
        }

        ids = {
            'phone': phone.id,
            'mail': mail.id
        }


    except IntegrityError:
        return JsonResponse({'added': added, 'error': 'contacto existente'})

return JsonResponse({'added': added, 'contact': contact, 'ids': ids})

Here is where I obtain the following error: Forbidden (CSRF cookie not set.): /smoke/add/

This is my settings.py config for cors-headers:

CORS_ORIGIN_WHITELIST = ["https://extension.runningdomain.com"]

CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'x-csrftoken'
)

CORS_ALLOW_CREDENTIALS = True

Thank you all guys for your support, and sorry for my english in advance.

Upvotes: 1

Views: 1308

Answers (1)

Rodrigo Reyes
Rodrigo Reyes

Reputation: 326

@wOxxOm again your sugestion help me.

For chrome extensions you can't make fetch requests from content-scripts, everything works fine when I changed the fetch process to the background-script.

So the solution is make requests from background scripts.

https://www.chromium.org/Home/chromium-security/extension-content-script-fetches

Upvotes: 1

Related Questions