Dernier combat en date, réussir à faire les requêtes entre mon back en Laravel et le front en Vue avec en intermédiaire Inertia qui s'occupe en partie des requêtes entre le back et le front sur un serveur distant en production (car cela fonctionne sans problème en local).
Car ça c'était la petite surprise au moment de la mise en production d'un de mes projets, je ne pensais pas que ça allait être aussi compliqué de régler cette erreur 419.
L'erreur sous-jacente (qui n'est pas "No Reason Phrase" ou "Entity Unknow" qui peut être retourné par la console développeur du navigateur) est en fait un mismatch entre le token CSRF du front et les données du token sur le back. En clair, le token s'assurant que le formulaire envoyé est bien celui qui est envoyé par le front n'est pas celui qui correspond à celui de l'utilisateur.
D'abord je pensais qu'il aurait suffit de le réattribuer au moment de l'envoi du formulaire mais ce n'était pas suffisant, il semble que le composant Form d'Inertia ne gère pas correctement Axios (ou alors je suis un manche avec Inertia/Laravel, c'est très possible).
Donc pour régler ce problème il y a plusieurs choses à faire. Déjà il ne faut plus utiliser le format suivant pour envoyer les formulaires au back :
const submit = () => {
form.post(route('book.create'))
}
Mais passer directement par Axios :
const submit = () => {
axios.post(route('book.create'), form)
}
Puis il faut ajouter cette balise dans votre fichier app.blade.php
pour avoir le token CSRF dans le template HTML (qui pourra être récupéré par la suite) :
<meta name="csrf-token" content="{{ csrf_token() }}">
Ensuite il faut surcharger axios
dans le fichier resource/js/bootstrap.js
pour ajouter la gestion des credentials dans les requêtes Axios et d'y insérer par défaut le token CSRF dans chaque requête passant par Axios :
import axios from 'axios'
window.axios = axios
window.axios.default.withCredentials = true
window.axios.default.headers.common = {
'X-Requested-With': 'XMLHttpRequest'
'X-XSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
}
Théoriquement ça devrait régler vos problèmes d'erreurs 419 CSRF Token mismatch.
Dans le cas éventuel où cela ne fonctionne toujours pas, il y a également cette astuce que j'ai trouvé sur dev.to où on peut pousser la régénération du token un peu plus loin.
Dans un premier temps il s'agit de créer un nouveau controlleur sur le back qui aura pour seul tâche de générer un nouveau token et de l'envoyer au front :
class RefreshCsrfTokenController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$request->session()->regenerateToken();
return response()->json();
}
}
Puis ajoute cette route dans le fichier routes/web.php
:
Route::get('/csrf-token', \App\Http\Controllers\RefreshCsrfTokenController::class);
Et enfin on modifie le fichier bootstrap.js
(celui du début) pour ajouter le code suivant :
import get from 'lodash/get'
axios.interceptors.response.use(response => response, async err => {
const status = get(err, 'response.status')
if (status === 419) {
// Refresh our session token
await axios.get('/csrf-token')
// Return a new request using the original request's configuration
return axios(err.response.config)
}
return Promise.reject(err)
})
Cela va intercepter tous les requêtes axios sortantes, et si la requête reçoit une erreur 419, il faut demander un nouveau token au back puis va envoyer à nouveau la requête. Cette fois si la requête devrait passer sans problème (et si c'est le cas, c'est qu'il y a probablement une erreur dans votre configuration Laravel).
À noter que si vous utilisez Inertia pour rendre certaines pages, il pourrait être nécessaire d'ajouter l'entête x-inertia
dans les exposed-headers
du fichier config/cors.php
car sinon les routes renvoyant du render Inertia risquent de s'afficher qu'en JSON.
Désormais vous ne devriez plus avoir un problème de csrf mismatch, au prix de devoir potentiellement gérer vous même manuellement l'update des composants Vue par contre.