Stop Cross-Site Request Forgery (CSRF) in its tracks. Learn how the @csrf directive works, why it's vital for your forms, and how to manage token expiration.
Previously in this course, we explored Protecting Routes with Middleware: A Laravel Beginner’s Guide to restrict access to authenticated users. Now that we have a secure authentication layer, we need to ensure that the data being submitted to our application is actually coming from our own forms.
Cross-Site Request Forgery (CSRF) is a vulnerability where a malicious website tricks a user's browser into performing an unwanted action on a different website where that user is currently authenticated.
Imagine you are logged into your Task Manager app. A malicious site you visit in another tab could contain a hidden form that sends a POST request to your-app.com/tasks/delete/1. Because your browser automatically includes your session cookies with that request, your app might think you intentionally clicked that delete button.
Laravel prevents this by requiring a secret, unique token for every state-changing request (POST, PUT, PATCH, DELETE). If the token is missing or invalid, Laravel rejects the request.
When you build a form in Laravel, you must include a hidden input field containing a CSRF token. The simplest way to do this is using the Blade @csrf directive.
Open your resources/views/tasks/create.blade.php file and add the directive inside your form:
HTMLstyle="color:#808080"><style="color:#4EC9B0">form action="/tasks" method="POST"> @csrf style="color:#808080"><style="color:#4EC9B0">label for="title">Task Namestyle="color:#808080"></style="color:#4EC9B0">label> style="color:#808080"><style="color:#4EC9B0">input type="text" name="title" id="title"> style="color:#808080"><style="color:#4EC9B0">button type="submit">Create Taskstyle="color:#808080"></style="color:#4EC9B0">button> style="color:#808080"></style="color:#4EC9B0">form>
When this page renders, Laravel replaces @csrf with an HTML input field that looks like this:
HTMLstyle="color:#808080"><style="color:#4EC9B0">input type="hidden" name="_token" value="a-long-random-string-of-characters">
When the user submits the form, this token is sent to the server. Laravel’s VerifyCsrfToken middleware (which is active by default on all web routes) compares the token in the request with the token stored in the user's current session. If they match, the request proceeds.
Sometimes, your users might leave a form open in their browser for a long time. If their session expires, the CSRF token becomes invalid. When they finally click "Submit," they will be greeted by a 419 Page Expired error.
This is a security feature, not a bug. To handle this gracefully:
config/session.php.TokenMismatchException in your app/Exceptions/Handler.php (or via global exception handling) to redirect the user back to the form with a helpful message: "Your session has expired. Please refresh the page and try again."Let's secure our Task Manager's "Create Task" form:
create.blade.php file.@csrf directive inside the <form> tags.419 Page Expired error—this confirms that Laravel's security middleware is working as intended.@csrf in a POST, PUT, or DELETE form. You will always get a 419 error.GET request to perform actions like deleting or updating data. CSRF protection only applies to state-changing methods. If you use GET for a delete action, you are bypassing this security layer entirely.@csrf directive. Instead, you must include the token in the request header. Laravel expects the token in the X-CSRF-TOKEN header.CSRF is a serious threat, but Laravel makes protection effortless. By using the @csrf directive in every state-changing form, you ensure that only requests originating from your own application are processed. Remember: if you see a 419 Page Expired error, the first thing to check is that your form includes the hidden token.
Up next, we’ll look at how to prevent mass assignment vulnerabilities, ensuring users can only update the database fields we explicitly allow.
Stop manually querying the database in your controllers. Learn how route model binding automatically injects Eloquent models into your routes.
Read moreLearn how to use Laravel middleware to secure your routes. We'll cover applying the auth middleware, protecting route groups, and managing redirects.
Understanding CSRF Protection
Updating Existing Records
Deleting Records
Using Named Routes
Task Manager: Completing CRUD Functionality
Introduction to Database Relationships
Querying Related Data
Handling File Uploads
Using Flash Messages for User Feedback
Task Manager: Adding Status and Priorities
Introduction to Artisan Commands
Debugging with Laravel Tinker
Understanding Service Providers
Using View Composers
Task Manager: Refactoring for Clean Code
Introduction to Testing
Testing Forms and Validation
Using Database Transactions
Handling Global Exceptions
Preparing for Production
Environment Security Best Practices
Managing Assets in Production
Task Manager: Deployment Preparation