Understanding CSRF Protection: Secure Your Laravel Forms
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.
What is CSRF?
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.
The @csrf Directive
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.
Handling Token Expiration
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:
- Keep Sessions Alive: If your application requires long form-filling times, consider extending your session lifetime in
config/session.php. - User Experience: You can catch the
TokenMismatchExceptionin yourapp/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."
Hands-on Exercise
Let's secure our Task Manager's "Create Task" form:
- Locate your existing
create.blade.phpfile. - Add the
@csrfdirective inside the<form>tags. - Try submitting the form without the directive. You will see a
419 Page Expirederror—this confirms that Laravel's security middleware is working as intended. - Add the directive back and verify that the task saves successfully.
Common Pitfalls
- Forgetting the Directive: The most common mistake is omitting
@csrfin a POST, PUT, or DELETE form. You will always get a 419 error. - Using GET for Actions: Never use a
GETrequest to perform actions like deleting or updating data. CSRF protection only applies to state-changing methods. If you useGETfor a delete action, you are bypassing this security layer entirely. - AJAX Requests: If you are using JavaScript to send data (like Axios or Fetch), you cannot use the
@csrfdirective. Instead, you must include the token in the request header. Laravel expects the token in theX-CSRF-TOKENheader.
Recap
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.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.