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

green-raven's avatar

Token Mismatch with vue-dropzone

If someone could help I would be most appreciative. I'm using vue-dropzone ^2.0.0 and Laravel 5.4.

I have the drag-and-drop portion working fine, but I always get a TokenMismatchException, even though I'm using the right token.

Here is the html:

<dropzone id="myVueDropzone" 
                   url="/uploadFile" 
                   @vdropzone-success="showSuccess" 
                   :headers="csrfHeader">
        
        <input type="hidden" name="csrf-token" :value="csrfToken">
</dropzone>

I've tried the name "_token" and "token" as well.

the data:

csrfToken: document.head.querySelector('meta[name="csrf-token"]').content,
csrfHeader: {
        'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content},

Vue toolbar says I have the right stuff:

csrfHeader: Object
    X-CSRF-TOKEN:"sVZ9px6OnXtQ6zdjYJ12yG7YmM6bYlidezTjJk9P"
csrfToken: "sVZ9px6OnXtQ6zdjYJ12yG7YmM6bYlidezTjJk9P"

I drag, it creates the upload, then gives me the exception

TokenMismatchException in VerifyCsrfToken.php line 68:

This setup is straight out of the docs. Is anyone familiar with this? I can share network info from the network tab if that would be helpful, or if you see some glaring error.

This seems more of a Laravel issue, but I could have put this in the Vue channel.

0 likes
9 replies
robrogers3's avatar

yep. share the network info. you need both of these sent:

  • X-CSRF-TOKEN
  • X-XSRF-TOKEN

also look at the source. in scripts tag in header. for the

and in console. what's this say: document.head.querySelector('meta[name="csrf-token"]').content

and this say: window.Laravel.csrfToken

and this say: document.cookie

make sure they all line up.

jenky's avatar

This works for me

:headers="{ 'X-CSRF-TOKEN': token }"

// .....
const token = document.head.querySelector('meta[name="csrf-token"]').content
green-raven's avatar

@robrogers3 I am seeing this in my request headers:

  ]
  "cookie" => array:1 [
    0 => "Idea-b555046a=85a9ce25-f9a9-4a20-9911-1283f4520e6b; XSRF-TOKEN=eyJpdiI6IlpOUUVPZmIrYUJpSERcL0p5YWJnc1pRPT0iLCJ2YWx1ZSI6Im9aSXJYckZxQUZVQTU5SGlCbEdXTjFOZm1ZZEdFRXJxZmtieVNnNENzVEhCeVBvVTdna0V2WHFNeUZGdUNYdFwvOEtiNGlHazhUMFBTblBmMmpNRGFrZz09IiwibWFjIjoiZmUzNGE4NDQ4Y2EzMzQxOGI1ZTEyODIwODA2MjMxNWQzYjkxMTRiNTc0ZGI1OTc4YjQxYjc3NDcwMDgyZTczNiJ9; laravel_session=eyJpdiI6IldWWGRiMkJSejZTNDdYV0tIcWpHd1E9PSIsInZhbHVlIjoiNnJ6UW4weXFUNFFNVGlyT1RPK0VEVEhYeG5RdmZxUnBnRVJkaWxoempWSmNuMXBaZXBKN3lZTmx3V01ROGJDRlBCVlFSQkNqY1N6dUhyXC9vWGdyQTBBPT0iLCJtYWMiOiI3Y2YwOTdkMjA5NmY4N2ZjNGNjMzBkOTk4YWUzOTRiNzA0MGUxMDFhZTZiODdjYzkwM2E3MDU2NDlmMWNjNjk4In0%3D"
  ]
]

The token looks to be Laravel's Hash of the actual token, which is this:

<meta name="csrf-token" content="LtvD5R6Tu98hPHn1chzg5RuRYtLSsuETDcqn3XC6">

But hashing the token would be correct would it not?

green-raven's avatar

So I ran a test, and put this in:

:headers="{ 'X-CSRF-TOKEN': 'bbb' }">

Then after the error, I check the request headers, and get this value:

XSRF-TOKEN=eyJpdiI6InA4eWthelFmVE44Tm9oUFNRRjlFaEE9PSIsInZhbHVlIjoidmExdUxkcEZIaGJEUUh3emsyMXJTb1Z4OXJYSnBUNXpybExpN0ZRUTdUWHpkSUg3ZGp0eUZXREJQRGwrelVOUzhHTTFpMUtxXC90WWVkaTdCakNRWUd3PT0iLCJtYWMiOiJjM2NkNjRmMWE4OWFmNTMzOWMyMzg3YTcyNmUzM2E5Yjk1N2YxYjhlZjcwNzFhNzc0NzVhZDUwYTI5MjdhNmU5In0%3D

But when I do

 \Hash::check('bbb', 'XSRF-TOKEN=eyJpdiI6InA4eWthelFmVE44Tm9oUFNRRjlFaEE9PSIsInZhbHVlIjoidmExdUxkcEZIaGJEUUh3emsyMXJTb1Z4OXJYSnBUNXpybExpN0ZRUTdUWHpkSUg3ZGp0eUZXREJQRGwrelVOUzhHTTFpMUtxXC90WWVkaTdCakNRWUd3PT0iLCJtYWMiOiJjM2NkNjRmMWE4OWFmNTMzOWMyMzg3YTcyNmUzM2E5Yjk1N2YxYjhlZjcwNzFhNzc0NzVhZDUwYTI5MjdhNmU5In0%3D')

I get false. So where is that token coming from?

robrogers3's avatar

ok. I was confused a bit. And I think I have it clearer now.

what is being compared is:

  • the session token which is stored under the '_token' key. this value is the same as the X-CSRF-TOKEN send by your browser.

  • the X-CSRF-TOKEN OR the XSRF-TOKEN in the request headers it checks if there is a X-CSRF-TOKN first. If not it uses the XSRF-TOKEN.

if it's the X-CSRF-TOKEN there is no decryption. Otherwise the token comes from the decrypted XSRF-TOKEN.

Which ever is selected becomes the request token, which is then compared against the session token. using hash_equals.

https://laravel.com/docs/5.4/csrf#csrf-x-xsrf-token

So what we need to see is what vue-dropzone does. by that I mean what it sends? then we can check that against what the session token is. via the 2 methods above.

So, please grab the request headers from chrome. and see what is sent.

green-raven's avatar

Thanks in advance for your help. Surely more people must be having some issue with file uploads from Vue to Laravel.

Here are my headers:

Request Headers

Accept:application/json
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8,fr;q=0.6
Cache-Control:no-cache
Connection:keep-alive
Content-Length:15692
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryQdgEyNCQoc3CX70I
Cookie:Idea-b555046a=85a9ce25-f9a9-4a20-9911-1283f4520e6b; XSRF-TOKEN=eyJpdiI6Ik4wd3ZwVVBPSkg0cWJ1b0JUZFZmV1E9PSIsInZhbHVlIjoiNFJuU0JrVzlwOUh5Vm1QVHZkVDBBWnU1SzhlU3ZLN2pKbldxd1czWWp6RDFzR2RHeHdcLzl3N3Z4Y3I5Tm1xVjVcL1d1V3ArampCV0E2Ujk0NTBibmYxZz09IiwibWFjIjoiMDc5MDg0NGZjYWIyOTRjM2FkODEwOWJhZDIyMzk0M2UxNTc1YzVhZjRmZjcwNjI0Nzg5ZWQ5MTRhNGFhMTk0YyJ9; laravel_session=eyJpdiI6IlJZaFZwNjB4dXFuMXluZ2RURkh5QVE9PSIsInZhbHVlIjoiU1JXdWdhMXMwM2tzVGxudzVcL1wvZmFjK0huaForYVdNV2NSem5KYndrZElsTWFsOUZmZkRxdmxrUTdyOTNZejZHOTVqYzdpbDI5Q0VCWmlMQkJ3dldhUT09IiwibWFjIjoiODQyZjk4ZDE3ODRlOTFjNTIwMGNkNTY4OTliYWExNjE1MTJkNDNlOThhMTE1M2Y3OGRlYTdkNzIzOWQwOWM3ZiJ9
Host:localhost:8000
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
X-Requested-With:XMLHttpRequest

I don't see the X-CSRF-TOKEN, nor do I see it in the payload from the hidden field:

<input type="hidden" name="csrf-token" :value="csrfToken">

payload:

------WebKitFormBoundaryQdgEyNCQoc3CX70I
Content-Disposition: form-data; name="file"; filename="Deployment Process.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document


------WebKitFormBoundaryQdgEyNCQoc3CX70I--
robrogers3's avatar
Level 37

well, there's your problem. it's this vue library. maybe.

What's your App.vue file? (or .vue file). PostBin it or create a jsbin.

where do you define those header props. in the same file right? anywho let's see it.

i've scanned the libs code for how he is 'using' dropzone'. Because dropzone itself requires you add it manually as a header. and then uses vanilla js for the ajax request.

note: i've used dropzone with vue a lot. I just put the config etc in some property on the vue object. also, I did a custom template. bottom line, it's not complicated.

green-raven's avatar

You got it! Nothing to do with code. You mentioned libraries, and I didn't see vue2-dropzone in my package.json. It may have been vue-dropzone without --save-dev.

I reinstalled and not hit the backend with this header:

X-CSRF-TOKEN:LtvD5R6Tu98hPHn1chzg5RuRYtLSsuETDcqn3XC6

Sorry for the runaround before hitting the real issue, but thank you for sticking with me!

Please or to participate in this conversation.