Understanding CSRF Tokens in Laravel
A Guide to CSRF Token Debugging
To save you a scroll and to sum it up
- The middleware checks if the request is a ‘read’ verb (GET, HEAD, OPTIONS), is a unit test, or has a URI that should bypass CSRF verification
- The middleware can be configured to exclude specific URIs from CSRF verification
- You can control if the XCSRF token should be added to the headers
If you want to know how this happens, let’s continue
If you have yet to stumble upon any CSRF issues in Laravel, I commend you and hope you never run into them.
During my time as a developer, these are the most common issues I faced when dealing with CSRF:
- Missing CSRF token
- Expired Session
- Mismatched Protocol (HTTP vs HTTPS)
- Incorrect SESSION_DOMAIN Configuration
If you want to learn more about CSRF and the security concerns around it, you can read more here.
What interests us now is to understand how Laravel checks for the token and what you should be looking at when debugging for these errors.
The CSRF Middleware
It all starts inside the middleware, where we want to:
- Determine if the HTTP request uses a ‘read’ verb.
- Determine if the application is running unit tests.
- Determine if the request has a URI that should pass through CSRF verification.
- Determine if the session and input CSRF tokens match
The isReading method will check for the HEAD, GET, and OPTIONS HTTP methods
The next method will check if we are running Unit Tests
The next method is one that we have access to by default from the App\Http\Middleware\VerifyCsrfToken.php. Here we can add values to the $except array and the Illuminate VerifyCsrfToken will omit them.
As we can see, it checks for every element inside the $except array and returns true if the current request URI matches an exempt URI.
The last check will see if the provided token matches the one from the session
After one of the checks passes and the CSRF token is valid, there is one more thing that happens.
It checks if it should attach an XSRF token to cookies.
By default, this is decided by a property on the class, called $addHttpCookie, which is a protected property.
This means we can control it just like we control the $except array :)
You can disable it or control it dynamically through your configs, like this: