CSRF Protection in Laravel – Tutorial
Introduction
Cross-Site Request Forgery (CSRF) is a common web vulnerability where a malicious website tricks an authenticated user into performing unintended actions (like changing an email, making a purchase, or deleting data) without their consent.
Example: If your app allows users to update their email at /user/email, an attacker could create a hidden form that automatically submits when the victim visits their page — changing the victim’s email to the attacker’s email.
Laravel provides built-in tools to prevent these kinds of attacks.
How the Attack Works (Without CSRF Protection)
Imagine this form exists on a malicious website:
<form action="https://your-app.com/user/email" method="POST">
<input type="email" value="hacker@example.com">
</form>
<script>
document.forms[0].submit();
</script>
If a logged-in user of your app visits that site, their email will be changed — because the request looks valid to the server.
Laravel’s Solution – CSRF Tokens
Laravel automatically generates a unique CSRF token for each user session.
- This token is stored in the session.
- It must be sent with every
POST,PUT,PATCH, orDELETErequest. - Laravel checks if the incoming token matches the session token.
If they don’t match → the request is blocked.
Using CSRF Tokens in Forms
When creating forms in Laravel, always include the CSRF token.
You can do this manually:
<form method="POST" action="/profile">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
But the easy way is to use the Blade @csrf directive:
<form method="POST" action="/profile">
@csrf
<input type="text" name="username">
<button type="submit">Save</button>
</form>
This ensures Laravel’s ValidateCsrfToken middleware will check the request.
Accessing the CSRF Token in Code
You can fetch the token directly if needed:
use Illuminate\Http\Request;
Route::get('/token', function (Request $request) {
$token = $request->session()->token(); // via session
$token = csrf_token(); // via helper function
return $token;
});
CSRF in Single Page Applications (SPA)
If you’re using Vue, React, or any SPA with Laravel as the backend:
- Use Laravel Sanctum for authentication and CSRF handling.
- It manages tokens automatically with cookies (
XSRF-TOKEN).
Excluding Routes from CSRF Protection
Sometimes, external services (like Stripe webhooks) need to POST data to your app but can’t send a CSRF token.
You can exclude routes:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
'http://example.com/foo/*',
]);
});
Only exclude trusted external routes, never user-facing forms.
CSRF Tokens with AJAX
When using jQuery or legacy JavaScript:
- Put the token in a meta tag:
<meta name="csrf-token" content="{{ csrf_token() }}"> - Configure jQuery to send it automatically:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
X-CSRF-TOKEN & X-XSRF-TOKEN
Laravel provides two headers for CSRF handling:
- X-CSRF-TOKEN → set manually in requests (e.g., via jQuery).
- X-XSRF-TOKEN → comes from the encrypted
XSRF-TOKENcookie (used by frameworks like Axios/Angular automatically).
Laravel’s resources/js/bootstrap.js configures Axios to send this header by default.
Important
- CSRF attacks trick authenticated users into making unwanted requests.
- Laravel protects against CSRF using session-based tokens.
- Always use
@csrfin Blade forms. - For APIs/SPAs → use Sanctum or rely on
X-XSRF-TOKENheaders. - Exclude only trusted routes like webhooks.
- AJAX requests should send the CSRF token in headers.
With this, your Laravel app is secure from CSRF attacks out of the box — you just need to use the built-in helpers correctly.
