Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 3, "ajax request" with fetch API, and CSRF

Tags:

ajax

symfony

In twig i generate a csrf token ({{ csrf_token('my_intention') }}).

In Javascript i call a controller with ajax, in fact with the Fetch API (Ajax xmlHttpRequest tried too), POST request. Argument name containing the token passed in the request is 'token=abcdef...'.

AJAX:

    var httpRequest = new XMLHttpRequest();
    httpRequest.onreadystatechange = function (data) {
        console.log(data);
    };

    httpRequest.open('POST', el.getAttribute("data-url"));
    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    httpRequest.send(.......);

Fetch API:

        fetch(el.getAttribute('data-url'), {
            method: 'post',
            headers: {
                "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
            },
            body: 'token=' + encodeURIComponent(el.getAttribute('data-token'))
        }).then(data => data.text()).then(data => {...}

In the controller action called i get the token sent as data from the POST request. I check the token like this in the controller:

    $token = $request->request->get('token');
    if (!$this->isCsrfTokenValid('my_intention', $token)) {
        throw new InvalidCsrfTokenException("error csrf 2");
    }

But Symfony say the token is not valid.

I'm not sure but i think token is not found in session variable. In isTokenValid() $this->storage->hasToken($token->getId()) return false.

In the browser, if i call the url directly, it's ok.

In twig i set the url to call in a data attribute like this data-url="{{ path('_check', {'id': transaction.id}) }}", then i read this data attribute from javascript and pass it to ajax/fetch function.

I tried ajax with jQuery $.post(... and it works. The only difference is Cookie:PHPSESSID... in the request header with jQuery not on my original code.

I don't understand, what is wrong with my code ?

Symfony 3.1.3

EDIT: resolved: i didn't pass credentials in headers request, so, no way for Symfony to find session and check token:

    fetch(el.getAttribute('data-url'), {
        method: 'post',
        headers: {
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "X-Requested-With": "XMLHttpRequest"
        },
        body: 'token=' + el.getAttribute('data-token'),
        credentials: 'include'
    }).then(data => data.text()).then(data => {
like image 373
krazitchek Avatar asked Oct 24 '25 19:10

krazitchek


1 Answers

Even if you found an answer to your issue, I recommend you to take a look at this bundle which handles the token verification based on a Cookie which is defined server-side and that you should pass in each asynchronous request.

https://github.com/dunglas/DunglasAngularCsrfBundle

like image 157
Keen Avatar answered Oct 26 '25 22:10

Keen