3

edit for future reference

Solved: on fetch request in script.js, I used Headers instead of headers, hence the "Missing csrf token" instead of missing or incorrect


So i'm building a project in Django for a "password manager" I've built my modules and correctly implemented the Item insertion via Django ModelForm, with csrftoken and all that.

Now i need to make an ajax request for updating the fields of the Item, and wanted to do on the same page so from Js when opening a LoginItem to edit the content I send a GET request as such

//fetch django for a form, and it sends back pre filled with initial values

  fetch(`edit/login=id`)
    .then((response) => response.text())
    .then((form) => {

      const edit_form = document.createElement('form');
      edit_form.setAttribute("method", "post");
      edit_form.setAttribute("id", "edittest");
      edit_form.innerHTML = form;
     //append the form

then in script.js, on submit:


    fetch(`edit/login=id}`, {
        method : "PUT",
        Headers:{
       //or "X-CSRFToken":event.target.querySelector('[name=csrfmiddlewaretoken]').value
            "X-CSRFToken": getCookie("csrftoken"),
            "Content-type": "application/json",
        },
        mode:"same-origin",
        body : JSON.stringify(body),
    })
    .then((response) => response.json())
    .then((data) => {
        console.log(data)
    })

in Views.py

        def edit_login(request, id):
        if request.method == GET:
           login = Entry.objects.get(id=id)
            // setting initial values for the form
           initial = {
                "title": login.title,
                "username": login.username,
                "password": login.password,
                "note": login.note,
                "folder": login.folder,
                "protected":login.protected,
                "favorite": login.favorite,
            }
            // setting the initial values to the ModelForm
            form = LoginForm(initial=edit)

            return render(request, 'vault/new_item.html', {"entry_form": form, 'uri_field': uri})
      
         else if request.method == "PUT":
             if request.user == login.owner:

             data = json.loads(request.body)

             print("test") # execution does not reach here

            return JsonResponse({"message": "Succesfully edited"}, status = 200 ) # oppure 204 = No content
         

I get Forbidden (CSRF token missing.): /edit/login=27

In the PUT fetch request I also tried instead of getCookie()

using "X-CSRFToken":event.target.querySelector('[name=csrfmiddlewaretoken]').value to get this form's csrf input value that gave me a different csrftoken than the previous.

Also if I inspect every element I open, i see each of them has a different csrftoken (ok, different requests, so I could fathom the error Incorrect Token, but the missing error i don't understand.

Also, if anyone has a hint on how to do this in an easier way, that'd be great, I have limited knowledge

Divroth
  • 49
  • 1
  • 5
  • Does this answer your question? [Forbidden (CSRF token missing or incorrect.):](https://stackoverflow.com/questions/36291186/forbidden-csrf-token-missing-or-incorrect) – Sunderam Dubey Nov 08 '22 at 02:44
  • https://stackoverflow.com/q/12731305 – Sunderam Dubey Nov 08 '22 at 02:45
  • I didn't seem to find a solution based on those articles that I had already looked through, What is buggling me is that inspecting the form I get, the csrf token is the same that i then console.log right before the put request. – Divroth Nov 08 '22 at 09:14
  • Fixed mistake by a friend, it was a typo in the fetch request, used `Headers` instead of `headers` – Divroth Nov 09 '22 at 00:11

1 Answers1

0

The simplest way I have solved this problem is by including the {{csrf_token}} value in the data without using @csrf_exempt decorator in Django(The decorator marks a view as being exempt from the protection ensured by the middleware.):

var csrftoken = "{{csrf_token}}";

 //Sample ajax request
$.ajax({
    url: url,
    type: 'POST',
    headers:{
    "X-CSRFToken": csrftoken
},
data: data,
cache: true,
});
  • Sorry but I can't seem to understand where should i put the first line ``var csrftoken = {{csrf_token}}`` Should that be in the page where I render the form inside a – Divroth Nov 08 '22 at 09:16
  • 1
    You can put it on the page where you will render the form inside a – Imam Hossain Roni Nov 08 '22 at 09:40
  • I added that but the form now disappeared... still I noticed another problem, the response I get from Django is ``
    `` But I didn't specify "post" method nor the action to ``new_element/`` I changed **Views.py** to point to a new *edit_login.html* containing the form that I pass from Django, but I can't understand where the "post" method is taken from, or why it has that path
    – Divroth Nov 08 '22 at 09:50