Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Drewlim7's avatar

How to fix CSRF token mismatch for patch ajax request 2nd time.

Hi, i am having 2 form in one page ( Multi-step form). First form is stored successfully, but when I tried to send 2nd form using patch ajax request with formdata ( because got file data ). However, i couldnt send it. I got include the @method('PATCH') @CSRF below my 2nd form. May I know why i cant send the form?

This is my partial js code,

if(next_step == true){
                $.ajax({
                    type: "PATCH",
                    headers: {'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content')},
                    url: "/"+current,
                    data: new FormData($(form)[0]),
                    processData: false,
                    contentType: false,
                    success: function(msg) {
                        if(msg != ""){
                            window.location.href = msg;
                        }
                    },
                    error: function (msg) {
                        var errors = msg.responseJSON;
            }
                });
            }
        }

This is what i got from debugger, {message: "CSRF token mismatch.", exception: "Symfony\Component\HttpKernel\Exception\HttpException",?

This is what i got from console log, PATCH http://localhost:8000/60 419 (unknown status) app.js

0 likes
25 replies
Nakov's avatar

@drewlim7 make sure that you have the meta tag in your head of the view:

<meta name="csrf-token" content="{{ csrf_token() }}" />

Then you can initialize it just once after loading the jQuery library, add this:

<script type="text/javascript">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
</script>

and you won't need to add it on each call. Let me know if it makes a difference?

2 likes
Drewlim7's avatar

@nakov I have the meta tag at the header. However when i changed to post instead of patch, it manages to redirect and process that form data but it doesn't what I want.

Nakov's avatar

@drewlim7 try this instead then:

 type: "post",
headers: {'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content'), '_method': 'patch'},
1 like
Drewlim7's avatar

@nakov Hmmm its working but why my first PATCH request is working but the 2nd doesnt? And how can I dont use the one you suggested because i want it to be PATCH request only. I have checked the formData.values(), it does contains method: _patch.

Nakov's avatar

@drewlim7 the _method should be in the header not in the form data. It is the same as if you were doing a traditional form.

From the documentation:

Since HTML forms can't make PUT, PATCH, or DELETE requests, you will need to add a hidden _method field to spoof these HTTP verbs. The @method Blade directive can create this field for you:

Drewlim7's avatar

@nakov but why my first ajax request is working? I didnt put the _method at the header. I did included it at view with the @method('PATCH'). This is my working first PATCH ajax request.

if(next_step == true){
                $.ajax({
                    type: "PATCH",
                    url: "/"+current,
                    data: form.serialize(),
                    success: function(msg) {
                        
                    },
                    error: function (msg) {
                        var errors = msg.responseJSON;
                        }
                });
            }
Nakov's avatar

@drewlim7 sorry yeah it should be part of the body.

so make sure that when you do this:

FormData($(form)[0])

it really contains the _method property as well.

Check the Network tab in your browser

Drewlim7's avatar

@nakov yea i did but when i tried to send 2nd ajax request in a same page but it does not go through with the configuration provided above.

Nakov's avatar

@drewlim7 Unfortunately I cannot debug your code in order to know. Might be because of using the same csrf token for both requests.

Drewlim7's avatar

@nakov Is there any ways to handle multiple ajax request using patch in the same page with same csrf token?

Nakov's avatar

@drewlim7 it should be possible, I am just guessing here my friend, you really need to debug this, inspect the network tab on your browser and compare what you miss on the request that is not working compared to the one that does work.

Drewlim7's avatar

@nakov the one not working is missing a Set-Cookie: XSRF-TOKEN from response header..

Drewlim7's avatar

@nakov Forgot to update you, previously when i added these

$.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

Then at controller there all my requests are empty, only an empty array is displayed when used dd to debug. Although the debugger network tab shows the formData but controller is not receiving any of these.

Nakov's avatar

@drewlim7 you need the request to be the same as the one that is working, the response is after the request is passing.

Not exactly the same of course, but the required fields should be there. I really cannot help much more my friend.

It does not makes sense when adding the header in the ajax setup the request to be empty, but once again, I cannot help not having the code to debug myself.

Drewlim7's avatar

@nakov It is very weird the patch request is sending to the controller but the $request->all() are empty. Will try to debug again. Thank you very much for your help!

DhineseG's avatar

I think csrf token is included inside the form itself and when submit the form ,there would be code to reset the form fields.Because of that only when posting second time csrf token is reset and shows the error ....

Zikri's avatar

Change secure to false in config/session.php

'secure' => env('SESSION_SECURE_COOKIE', false),
NiloLeon's avatar

I think u had to delete this

new FormData($(form)[0])
danielg516's avatar

@drewlim7 Make sure that your form don't be inside a tr or table tag, I had the same problem and i realized that the form tag was closed without any element.

ModernCoding's avatar
Level 1

@drewlim7

Hi,

I am new to this forum.

Did you solve your issue?

I had the same issue, especially the empty array after using $.ajaxSetup and I finally found the solution thanks to good luck!

Two things to know:

  • you don't need $.ajaxSetup; as long as you have that "_token" in your formData, it is perfectly fine. It can be either the content attribute of your meta tag or the @csrf of your blade view

  • $.ajax & Laravel ? Forget PATCH, DELETE, PUT and all that stuff; HTTP protocol only knows GET and P(R)OST

So for your ajax call, always stick to type: 'post'.

If you need to call in PATCH or DELETE mode, then pass the "_method" in your formData and Laravel will handle it as a PATCH call.

To check you have everything you need in your formData:

for (var key of formData.entries()) {
    console.log(key[0] + ', ' + key[1]);
}

You should see something like in Chrome Console:

_token, YOUR_TOKEN _method, patch id, 9 label, Toto label_kh, Titi

At the end, you ajax call should be:

$.ajax({
  
  url: [your url],
  type: 'post',
  data: formData,
  processData: false,
  contentType: false,
  

  success: (object) => {...},
  error: (error) => {...},
  complete: () => {...}

})

Hope this helps.

1 like
GGeorge's avatar

Thanks a million, you have helped solve similar issue. I've now understood it

1 like
Drewlim7's avatar

Hi @moderncoding , yes, I have solved my problem long time ago by replacing them from PATCH to a POST type request and POST method at web.php. Thanks for your suggestions and clear explanation.

1 like
ModernCoding's avatar

Hi @drewlim7

Glad you solved your problem this way.

Short before I solved the issue, I was about to do the same as you, which is not the best practice but only a temporary way to overcome the problem until finding the right solution.

POST is right if you CREATE. But when you UPDATE, you should stick to the PATCH protocol; same speech for DELETE.

Cheers.

Please or to participate in this conversation.