Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add Django's CSRF token to the header of a jQuery POST request?

I'm trying to make a Django form with dynamically pre-populated fields: that is, when one field (checkin_type) gets selected from a drop-down menu, other fields get automatically pre-populated with corresponding data. To this end, I would like to send a POST request to the server as soon as a drop-down option is selected.

So far I've tried the following template (following https://docs.djangoproject.com/en/2.0/ref/csrf/):

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
<script>
    $(document).ready(function(){
        var csrftoken = Cookies.get('csrftoken');

        $(".auto-submit").change(function() {
            $.post({
                url: "{% url 'get-checkin-type' %}",
                data: $(".auto-submit option:selected").val(),
                headers: {
                    X-CSRFToken: csrftoken
                }
            })
        });
    });
</script>


<form action="" method="post">{% csrf_token %}
    {% for field in form %}
        <div class="{% if field.name == 'checkin_type' %}auto-submit{% endif %}">
            {{ field.errors }}
            {{ field.label_tag }}
            {{ field }}
        </div>
    {% endfor %}
    <input type="submit" value="Send message" />
</form>

However, when I select a drop-down option I get a

new:17 Uncaught SyntaxError: Unexpected token -

which emanates from the X-CSRFToken: csrftoken line:

enter image description here

Can someone point out to me what is wrong with this code? (I tried looking it up from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token but so far couldn't figure it out).

By the way, it seems from jQuery add CSRF token to all $.post() requests' data that one can also add the CSRF token to the POST request's data, but this doesn't seem like the most elegant approach to me, and the docs state that

For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token.

like image 746
Kurt Peek Avatar asked Mar 01 '18 06:03

Kurt Peek


2 Answers

You are missing single quote, Try like following.

$(".auto-submit").change(function() {
    $.post({
        url: "{% url 'get-checkin-type' %}",
        data: $(".auto-submit option:selected").val(),
        headers: {
            'X-CSRFToken': csrftoken
        }
    })
});
like image 182
PSK Avatar answered Oct 22 '22 23:10

PSK


PSK's solution works, but for the sake of completeness, here is the approach as outlined by the Django docs after reading a bit further (from https://docs.djangoproject.com/en/2.0/ref/csrf/#setting-the-token-on-the-ajax-request) which uses a .ajaxSetup to cover all requests once and for all:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
<script>
    $(document).ready(function(){
        var csrftoken = Cookies.get('csrftoken');

        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });

        $(".auto-submit").change(function() {
            $.post({
                url: "{% url 'get-checkin-type' %}",
                data: $(".auto-submit option:selected").val(),
            })
        });
    });
</script>
like image 3
Kurt Peek Avatar answered Oct 23 '22 00:10

Kurt Peek