Mastering Laravel CSRF Protection

aravel Laravel Views & Blade Templates – Beginner’s Guide

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, or DELETE request.
  • 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:

  1. Put the token in a meta tag: <meta name="csrf-token" content="{{ csrf_token() }}">
  2. 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-TOKEN cookie (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 @csrf in Blade forms.
  • For APIs/SPAs → use Sanctum or rely on X-XSRF-TOKEN headers.
  • 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.