Introduction
CSRF (Cross-Site Request Forgery) is an attack that tricks an authenticated user into making unintended requests by impersonating them. For example, suppose your application has aPOST /user/email route that accepts an email address change. If an attacker embeds a form on another site that automatically submits to this URL, the user’s email address could be changed without them noticing.
In Laravel 13, CSRF protection is enabled by default via a mechanism included in the web middleware group.
Preventing CSRF attacks
Laravel’sPreventRequestForgery middleware protects against CSRF using two layers:
- Origin verification (the
Sec-Fetch-Siteheader) - Token verification (per-session CSRF token)
Origin verification
Laravel first checks theSec-Fetch-Site header to determine whether the request is from the same origin. This is especially effective in HTTPS environments.
If Origin verification passes, the request is allowed at that point. If not, CSRF token verification is performed as before.
Origin-only mode
You can also disable the fallback to token verification and make the decision purely based on Origin verification.403 instead of 419.
If you want to allow same-site requests (such as between subdomains), set allowSameSite.
Token verification
Laravel generates a CSRF token per session. You can retrieve it viacsrf_token() or from the session.
POST, PUT, PATCH, or DELETE forms in web routes, always include @csrf.
Excluding URIs
For requests sent from external services like Stripe webhooks, you may want to exclude certain URIs from CSRF protection.Where possible, place webhook routes outside the
web middleware group and keep exclusion settings to a minimum.X-CSRF-TOKEN header
In addition to the_token form field, Laravel also verifies the X-CSRF-TOKEN header.
First, output the token in a meta tag.
X-XSRF-TOKEN header
Laravel also sends an encryptedXSRF-TOKEN cookie. Axios and Angular can automatically set this value in the X-XSRF-TOKEN header on same-origin requests.
For that reason, CSRF protection may work in SPA or AJAX implementations without manually setting the header.