Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Morgon's avatar

Creating an Ajax CSRF Middleware

I'm attempting to create a Middleware based on the existing CSRF Middleware (I'm trying to avoid touching files that still may change), and I'm having some issues.

I've created app/Http/Middleware/VerifyCsrfAjaxToken.php with the following:

<?php namespace App\Http\Middleware;

class VerifyCsrfAjaxToken extends VerifyCsrfToken
{
    protected function tokensMatch($request)
    {
        return $request->session()->token() == $request->header('x-csrf-token');
    }
} 

I then added the following to RouteServiceProvider

protected $middleware = [
    // existing middleware
    'csrf.ajax' => 'App\Http\Middleware\VerifyCsrfAjaxToken'
]

And finally, my Controller route definition

    /**
     * @Post("profile/expand", as="expandProfile")
     * @Middleware("csrf.ajax")
     *
     * @return string
     */
    public function expandProfile()
    {
        return 'expanded view';
    }

However, when I Ajax in from the view that calls this route, the TokenMismatchException is being thrown from VerifyCsrfToken, and my Ajax Middleware is not being called at all (confirmed by dd() within my Middleware's tokensMatch method not executing).

Is there something basic (or not-so-basic) that I'm missing in this equation?

0 likes
10 replies
DCV's avatar

If you haven't changed your Http\Kernel.php stack, the VerifyCsrfToken middleware is going to be called every time you make a non-GET request. So, unless you are explicitly setting a _token parameter on your request, you will receive a TokenMismatchException. It looks like your middleware is acting in addition to the standard VerifyCsrfToken middleware check.

nolros's avatar

@Morgon working on something similar, if you get it working please post solution.

afrayedknot's avatar

In the latest commit from Taylor - the VerifyCsrfToken is now part of your middleware stack - which means it will always be fired. You could remove it from the stack - and call it manually on certain routes - but I think your over-complicating it.

Just change the VerifyCsrfToken middleware. It sits inside your app, rather than the framework for a reason - it is designed to be able to be customised.

protected function tokensMatch($request)
 {
  return (($request->session()->token() == $request->input('_token')) ||
          ($request->session()->token() == $request->header('x-csrf-token')));
 }

One line of code - and your done.

vjacob's avatar

No need to extend, just change the method

/**
 * Determine if the session and input CSRF tokens match.
 *
 * @param \Illuminate\Http\Request $request
 * @return bool
 */
protected function tokensMatch($request)
{
    // If request is an ajax request, then check to see if token matches token provider in
    // the header. This way, we can use CSRF protection in ajax requests also.
    $token = $request->ajax() ? $request->header('X-CSRF-Token') : $request->input('_token');

    return $request->session()->token() == $token;
}
1 like
Morgon's avatar

So @dv/@theshiftexchange - you're saying that the CSRF Middleware runs implicitly from any POST request? I guess I get the rationale, but not exactly what I was hoping - would be nice to be able to separate them.

But what's bothering me is that I can't seem to control the CSRF Middleware at all - I saw syntax like @Middleware("csrf", only={"index"}), but that doesn't seem to work, either.

I'd like to have a little more control over the CSRF functionality (just in general, so I can understand it more).. anyone have any thoughts there?

afrayedknot's avatar

"But what's bothering me is that I can't seem to control the CSRF Middleware at all - I saw syntax like @Middleware("csrf", only={"index"}), but that doesn't seem to work, either."

@Morgon - the Middleware stack has been rewritten at least twice by Taylor - so the code you are referring to is no longer directly applicable.

It is difficult to give you an answer on what should be done until L5 hits beta.

"I'd like to have a little more control over the CSRF functionality"

You already have full control - just edit the VerifyCsrfToken file - that is where all the CSRF logic belongs.

Morgon's avatar

But that's modifying what I consider a 'core' file. Whatever happened to 'Open to extension, but closed for modification'?

DCV's avatar

@Morgon - That isn't a core file. It is within your app directory, and is meant to be edited by your application as needed. You can do as the others have stated and edit it to your liking.

If you want to continue down the route you are expecting (which is being able to specify which routes are under CSRF protection), you can edit app\Http\Kernel.php and remove the VerifyCsrfToken.php reference from your Middleware stack. Then you can specify on your own middle via your annotation:

@Middleware("csrf", only={"index"})
afrayedknot's avatar

@Morgon - to further what @DV said - the file is given so you can modify it - it is just sensible defaults provided by Taylor for Laravel5. If it was fixed, then it wouldn't be in the app folder - it would be a function built into the framework.

There are many reasons/cases why you would modify the default Middleware to suit various application needs.

Also - as I mention - you could remove the Middleware from the stack, and call it manually on your route - so then you achieve your 'open to extension, closed for modification` goal - but I think you'll be making it more complicated than it needs to be.

thiduzz's avatar

Just to let you guys know that VerifyCsrfToken isn't on the middleware folder of L5 structure (at least not in the project i started 2 days ago). And the middleware stack looks just like this:

protected $middleware = [
    'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
    'Illuminate\Cookie\Middleware\EncryptCookies',
    'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
    'Illuminate\Session\Middleware\StartSession',
    'Illuminate\View\Middleware\ShareErrorsFromSession',
    'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
];

Please or to participate in this conversation.