on Vue-Laravel-based environment,CSRF token is initialized server-side -non-sanctum, one token per run-:
routes/web.php
Route::get('csrf-token' , function(){
$token = csrf_token();
return response()->json(['token' => $token])->cookie('XSRF-TOKEN'$token,0,'/',null,false,false, false, 'lax');
});
CSRF-token-request is excluded from token verification middleware:
middleware/verifyCsrfToken.php
protected $except = [
'csrf-token',
'api/*'
];
Token checked with every request sent to server:
middleware/verifyCsrfToken.php
protected function tokenmatches($request) : bool{
$csrftoken = $request->session()->token();
if (! is_string($csrftoken)) {
return false;
}
// Accept token via header(s)
$header1 = $request->header('X-CSRF-TOKEN');
$header2 = $request->header('X-XSRF-TOKEN');
if (is_string($header1) && hash_equals($csrftoken, $header1)) {
return true;
}
if (is_string($header2) && hash_equals($csrftoken, $header2)) {
return true;
}
// Accept token from cookie (frontend frameworks often store token in XSRF-TOKEN cookie)
$cookie = $request->cookie('XSRF-TOKEN');
if (is_string($cookie)) {
$cookie = rawurldecode($cookie);
if (hash_equals($csrftoken, $cookie)) {
return true;
}
}
return false;
}
public function handle(Request $request, Closure $next): Response
{
// Respect excluded paths
foreach ($this->except as $except) {
if ($request->is($except)) {
return $next($request);
}
}
if ($this->tokenmatches($request)) {
return $next($request);
}
abort(419, 'CSRF token mismatch.');
}
Session configuration:
.env
SESSION_DRIVER=database # file, cookie, database, redis, memcached, array
SESSION_ENCRYPT=false
SESSION_PATH=/ # cookie path
SESSION_LIFETIME=120 # minutes
SESSION_EXPIRY_ON_CLOSE=false # true/false (expire on browser close)
SESSION_SECURE_COOKIE= false # true in prod with HTTPS, false on local HTTP
SESSION_HTTP_ONLY=false # true: JS can't read cookie
SESSION_SAME_SITE= lax # lax | strict | none (note: none requires secure=true)
SESSION_DOMAIN=null # e.g. .example.com or null (for localhost)
SESSION_COOKIE=laravel_session # cookie name
config/session.php
return [
'driver' => env('SESSION_DRIVER', 'database'),
'lifetime' => (int) env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
'encrypt' => env('SESSION_ENCRYPT', false),
'files' => storage_path('framework/sessions'),
'table' => env('SESSION_TABLE', 'sessions'),
'store' => env('SESSION_STORE'),
'lottery' => [2, 100],
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => env('SESSION_PATH', '/'),
'domain' => env('SESSION_DOMAIN' , null),
'secure' => env('SESSION_SECURE_COOKIE' , false),
'http_only' => env('SESSION_HTTP_ONLY', false),
'same_site' => env('SESSION_SAME_SITE', 'lax'),
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
];
Client-side: *server proxy applied to //vite.config.js *axios request is used -axios request configured manually on //globalStore/sharedStore.js- axios configuration:
globalStore/sharedStore.js
axios.defaults.baseURL = 'http://localhost:8000';
axios.defaults.withCredentials = true; // send cookies
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.withCredentials = true; // important if using Sanctum or cookie-based auth
axios.defaults.timeout = 10000
CSRF token request:
globalStore/sharedStore.js
async function csrftoken() {
try {
const { data: token } = await axios.get('csrf-token');
axios.defaults.headers.common['X-CSRF-TOKEN'] = token.token;
}catch(error)
.............
Request cookie isn't formed, token is regenerated with each request, on invoking PUT,POST,PATCH request,it gets CSRF token mismatch.