-2

I think the problem is in part due to the fact im not using the HTML template tag since, I'm creating a project using the JS generating the HTML from there. For addressing this in the HTML i added this script(before the js script I use):

<script> var csrfToken = '{{ csrf_token }}'; </script>

Im using the following script after the form code to send the information to my django project:

const apiSendDataUser = (event) => {
    event.preventDefault();
    
    const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
    const formData = new FormData (event.target);
    fetch('https://127.0.0.1:8000/myProject/post_user',{
        method: 'POST',
        body: formData,
        headers: {
            'X-CSRFToken': csrfToken
        }
    })
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error('Error: ' + response.status);
        }
    })
    .then(data => {
        // Handle the response data
        console.log(data);
    })
    .catch(error => {
        // Handle any errors
        console.error(error);
    });
};

And finally, the post_user function on the views.py is:

@require_POST 

def post_user(request):

    try:
        email = request.POST['email']
        if not User.objects.filter(email).exists() :

            username = request.POST['username']
            password = request.POST['password']
            
            User.objects.create_user(username=username, password=password, email=email)

        return JsonResponse(
            {
                "success":True,
                "message": "Usuario añadido."
            }
            )
    
    except Exception as e:
        return JsonResponse({
            "success": False,
            "message": e.args[0]
        }, status=404) 

I've tried some options you have given me, for example I even gave up trying on JS and just placed the token in a form in the HTML, but it doesnt work, retrieves me 403: CSRF token missing. That is so weird since I've found the actual token and its value:

<input type="hidden" name="csrfmiddlewaretoken" value="VNHOnecTJVc61dUGpZaZ6X02yyGTayY6Bnnauqzv2NAmFi3XfhhU5Rj2El5kVtEl">

And this is it, if you got any idea what could be happening It would be nice to read you!

Daniel N
  • 7
  • 2

2 Answers2

0

The CSRF token is included in the HTML of the Django-rendered webpage as a cookie. You're trying to include it in your script using a Django template tag, but since the form is generated using JavaScript, this token is not included correctly.

Here's how you can retrieve the CSRF token from the cookie:

function get_cookie(n) {
    if (!document.cookie || document.cookie !== '')
      return null;
    
    let cookies = document.cookie.split(';');
    for (let i = 0; i < cookies.length; i++) {
      let cookie = cookies[i].trim();
      
      if (cookie.substring(0, name.length + 1) === (name + '='))
       return decodeURIComponent(cookie.substring(name.length + 1));
     
   }
}
let csrfToken = getCookie('csrftoken');

After you can use it in the fetch request.

fetch('https://127.0.0.1:8000/myProject/post_user',{
    method: 'POST',
    body: formData,
    headers: {
        'X-CSRFToken': csrfToken
    }
})

Also, check if Django settings have CSRF_COOKIE_NAME equal to csrftoken. If it has another value, you need to replace it when calling the get_cookie function.

If this still doesn't work, make sure that your Django view is properly set up to handle CSRF. The Django @csrf_exempt decorator can be used to test it.

  • So instead of getting the csrfToken variable from the querySelector, i should get it from the global variable called csrfToken? Btw in let csrfToken you call getCookie and not get_cookie, you meant there the call for the function right? sorry I'm new and all this is complicated sometimes. – Daniel N Jul 13 '23 at 10:49
  • 1
    Dmytro Kachurovskyi - This answer appears likely to have been written (entirely or partially) by AI (e.g., ChatGPT). If you used an AI tool to assist with any answer, I would encourage you to delete it, as [posting of AI-generated content is banned here](//meta.stackoverflow.com/q/421831). **Readers should review this answer carefully and critically, as AI-generated information often contains fundamental errors and misinformation.** If you observe quality issues and/or have reason to believe that this answer was AI-generated, please leave feedback accordingly. – NotTheDr01ds Jul 13 '23 at 23:18
0

Answer
In order to use const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
you have to have {% csrf_token %} somewhere in your HTML template.

Why this works
When Django sees this it will replace {% csrf_token %} with something like
<input type="hidden" name="csrfmiddlewaretoken" value=".............................">,

which your JavaScript can then get using the QuerySelector. Usually it is placed within the <form>:

<form>
    {% csrf_token %}
    ...
</form>

But since you are using JavaScript to send the form, it can be placed anywhere in your HTML:

<div>{% csrf_token %}</div>

Why your code does not work
When Django sees this: <script> var csrfToken = '{{ csrf_token }}'; </script> it will replace {{ csrf_token }} with a random value, the actual token, so it will look something like this:

<script> var csrfToken = 'some_random_string_which_is_the_token'; </script>

Note the difference. Here with {{ csrf_token }} your querySelector fails, since there is no hidden input generated with the name=csrfmiddlewaretoken, which is what happens with {% csrf_token %}

raphael
  • 2,469
  • 2
  • 7
  • 19