How to pass laravel CSRF token value to vue
I have this form where the user should only type text inside a text area:
<form action="#" v-on:submit="postStatus">{{-- Name of the method in Vue.js --}}
<div class="form-group">
<textarea class="form-control" rows="5" maxlength="140" autofocus placeholder="What are you upto?" required v-model="post"></textarea>
</div>
<input type="submit" value="Post" class="form-control btn btn-info">
{{ csrf_field() }}
</form>
Then, I have this script code where I am using vue.js with ajax in order to pass that text into a controller and eventually save it into the database:
//when we actually submit the form, we want to catch the action
new Vue({
el : '#timeline',
data : {
post : '',
},
http : {
headers: {
'X-CSRF-Token': $('meta[name=_token]').attr('content')
}
},
methods : {
postStatus : function (e) {
e.preventDefault();
console.log('Posted: '+this.post+ '. Token: '+this.token);
$.ajax({
url : '/posts',
type : 'post',
dataType : 'json',
data : {
'body' : this.post,
}
});
}
},
});
However, this doesn't work so far, since there's this token mismatch exception. I don't know how to make it work. How to pass this token value to the controller. I have tried the following:
1) inside the form, I have added a vue name to the token:
<input type="hidden" name="_token" value="YzXAnwBñC7qPK9kg7MGGIUzznEOCi2dTnG9h9çpB" v-model="token">
2) I have tried to pass this token value into the vue:
//when we actually submit the form, we want to catch the action
new Vue({
el : '#timeline',
data : {
post : '',
token : '',
},
methods : {
postStatus : function (e) {
e.preventDefault();
console.log('Posted: '+this.post+ '. Token: '+this.token);
$.ajax({
url : '/posts',
type : 'post',
dataType : 'json',
data : {
'body' : this.post,
'_token': this.token,
}
});
}
},
});
... but in the console, vue doesn't even catch it :(
This leads me to the following error:
TokenMismatchException in VerifyCsrfToken.php line 68:
How do I fix it? Any ideas?
Solution 1:
Very Easy Solution
Just add a hidden field inside the form. An Example
<form id="logout-form" action="/logout" method="POST" style="display: none;">
<input type="hidden" name="_token" :value="csrf">
</form>
Now add csrf
variable inside script at the vue file, like this. (Remember, it must be inside data).
<script>
export default {
data: () => ({
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
}),
}
</script>
N.B. You will see a meta tag in your blade.php
file like this.
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
If there is nothing like this, you need to place it there.
Solution 2:
A better way is simply to pass the csrf token via a slot into the vue component.
In blade.php file:
@extends('layouts.app')
@section('content')
<my-vue-component>
{{ csrf_field() }}
</my-vue-component>
@endsection
In MyVueComponent.vue
<form role="form">
<slot>
<!-- CSRF gets injected into this slot -->
</slot>
<!-- form fields here -->
</form>
Solution 3:
My solution to this is that all vue components get csrf token right before a request is made. I put this in my bootstrap.js file.
Vue.http.interceptors.push((request, next) => {
request.headers.set('X-CSRF-TOKEN', CoolApp.csrfToken);
next();
});
Then have a class CoolApp.php
public function getScriptVariables()
{
return json_encode([
'csrfToken' => csrf_token(),
]);
}