Method for setting CSRF token on client
jasonvarga opened this issue · 4 comments
Laravel Precognition Plugin Version
0.5.2
Laravel Version
10.35.0
Plugin
Alpine
Description
We have a setup where the CSRF token or cookie may not be available. (We're serving statically cached html).
We need a way to set the X-CSRF-Token
header somehow.
I see that there's a way to set the url argument using a function. I think if we could set the config argument with a function, that'll probably work too.
We can grab the token via an ajax request to a route that just returns it.
Route::get('token', fn () => csrf_token());
const getConfig = function () {
return { headers: { 'X-CSRF-TOKEN': getTokenViaAjax() } };
}
// ...
$form('post', '/the-url', {}, getConfig);
Or maybe a way of modifying the client after the fact.
document.addEventListener('got-csrf-token', () => {
$form.setHeaders(...);
});
Or maybe there's already a way to do this. Thanks!
Steps To Reproduce
- Create a route outside of your web routes, so that there is no session.
- Output
{{ csrf_token() }}
to the page, see that its blank. - Create a form with precognition. The requests will give
419
responses.
Someone found a solution for us that seems to work.
In the custom event I mentioned, we would update the token on an html element.
Then we can provide an object with a toString
method to the header, which will grab the token from the element.
$form('post', '/the-url', {}, {
headers: {
'X-CSRF-Token': {
toString: () => document.getElementById('the-element').value
}
}
});
@jasonvarga sorry I didn't see your issue here.
Sounds like you have it solved, but for anyone seeing this I would also recommend doing this globally somewhere via the Axios client configuration...
import { client } from 'laravel-precognition-{package_flavour}';
getCsrfToken().then(csrfToken => {
client.axios().defaults.headers.common['X-CSRF-TOKEN'] = csrfToken;
})
Thanks Tim.
In our case, we are injecting some JS into the html response via a package. We don't have access to their JS build process so we can't import { client }
but this is good to know anyway!
Gotcha! Another option which might feel a little cleaner is to set the _token
input on the form, either by injecting a hidden HTML input into the form like @csrf
does or adding it in the form data. This would require the the-element
to be available on load.
$form('post', '/the-url', {
_token: document.getElementById('the-element').value,
});
Either way, a few options depending on what you need.