Search code examples
jqueryhtmlspringcsrfthymeleaf

Use of Spring CSRF with ajax Rest call and HTML page with Thymeleaf


I'm using Spring Security with CSRF and I have a problem with some POST call in my javascript. For my page I use Thymeleaf and HTML 5, for the Rest call to my controller I use jQuery.ajax. If I use the ajax call for my form like this:

$(function() {
    $("#saveCarButton").click(
            function() {
                var form = $("#addCarForm");        
                $.ajax({
                    type : "POST",
                    url : form.attr("action"),
                    data : form.serialize(),
                    // all right with rest call
                    success : function(data) {...}  
                    //error during rest call
                    error : function(data) {
                        window.location.href = "/500";
                    }
                });
            });
});

everything works fine, but when I call for example this function:

jQuery.ajax({
        url : 'upload',
        type: 'POST',
        contentType: false,
        processData: false,
        data:formData,
        beforeSend:function(xhr) {
            waitingModal.showPleaseWait();
        },  
        success: function(data,status,xhr){...}
        error: function(xhr,status,e){
        }
    }).complete(function() {
        //add timeout because otherwise user could see a too fast waiting modal
        setTimeout(function(){
            waitingModal.hidePleaseWait();
        }, 1000);
    });

I receive error 403. Maybe with form, using thymeleaf, it works fine but with the second type of request I have to add CSRF token. I tried with

var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");

and in my html page I added

!--  -->
<meta name="_csrf" th:content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>

Why does it with the form work? I don't have to add nothing when I use form? Is it danger that _csrf and _csrf_header are visible with dev tool of browser? thanks


Solution

  • This is most likely due to the fact no CSRF token is being sent through hence the 403.

    This is the fix that does the trick for these sorts of things (at least for me).

    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e,xhr,options) {
       xhr.setRequestHeader(header, token);
    }
    

    In summary it attaches the CSRF token to any post request you do via ajax.