[L5] Avoiding CSRF middleware on API POST routes

Published 3 years ago by alexleonard

I've just started setting up an API in an L5 application and if I try to create a POST route on the API I instantly get TokenMismatchException in VerifyCsrfToken.php line 45

I did notice this laravel/laravel commit today which I'm guessing is probably related.

Anyone know how to stop CSRF verification from being called on certain routes, or do I need to wait to see how the cookie will crumble?

Thanks!

coopers98

Right here with you on this one. To allow me to keep moving forward, I just commented out the Csrf middleware in app/Http/Kernel.php

coopers98

Another reply since I forgot to subscribe on the first one.

alexleonard

Regarding CSRF in AJAX requests, Taylor says:

Override the default CSRF protection with your own implementation - then list your own implementation in the kernel list of middleware. But really you should have CSRF token on Ajax requests.

So I guess for the API end of things we need to override CSRF with a custom implementation which can be called on certain routes. Not 100% sure how to approach that, but will investigate today.

nWidart

Adding the following fixed the token mismatch error for me:

$.ajaxSetup({
    headers: {
        'X-XSRF-TOKEN': $('input[name="_token"]').val()
    }
});

But created a new DecryptException error.

coopers98

So in my case, the API calls could be coming from a number of places, not necessarily an AJAX call (although that is possible as well). It could be coming from another domain, mobile device, etc.

alexleonard

Has anyone worked out a proper way to go about this? I'll comment out VerifyCsrfToken in App\Http\Kernel for the short term and get the API POST functionality working, but I'll need to put the token verification back in.

It would be great if we could do some sort of reverse-when in routes, like

$router->when('api/*', 'exclude:csrf', ['POST']);

Only other thing I can think of is somehow getting API routes to load a different Kernel which would allow specification of $middleware excluding the VerifyCsrfToken.

nWidart

I temporarily also commented out the middleware. But this option isn't viable for longterm.

lukasoppermann

Same problem here, any good solutions yet?

trevorg

I'm also curious about this. For an API, I want to not have the CSRF token validation, and also I don't want sessions, so in the kernel.php file I've commented those out:

//'Illuminate\Session\Middleware\StartSession',
  //'Illuminate\View\Middleware\ShareErrorsFromSession',
  //'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',

But of course, I'll need those for the frontend routes. I figure I can just add them back in at the routes level. Not sure if this is the best way to do it, but I can't find another way.

mglinski

If you don't need a middleware executed globally: setup each middleware in your controller files as needed.

Extend the controller base class with what you generally need and make some extra functions there to describe what parts of your app will need a specific middleware:

protected function _setupApiMiddleware(){}

protected function _setupFrontendMiddleware(){}

Then call those functions in your controller constructors or methods when needed.

bestmomo
bestmomo
3 years ago (350,700 XP)

This post is redundant with this one.

nWidart

Since this post was created pretty much one week earlier, I'd say it's the other way arround @bestmomo :)

My temporary solution is to add a check for the ajax calls:

if ($request->method() == 'GET' || $this->tokensMatch($request) || $request->ajax())
{
    return $next($request);
}
bestmomo
bestmomo
3 years ago (350,700 XP)

Btw it's not so hard to send token with Ajax...

pmall
pmall
3 years ago (547,345 XP)

@bestmomo I agree it's easy to send the token with ajax. You should do it. The problem is with api calls.

billmn
billmn
3 years ago (83,800 XP)

With latest updates you can avoid CSRF on API working on VerifyCsrfToken class in App\Http\Middleware ( https://github.com/laravel/laravel/blob/develop/app/Http/Middleware/VerifyCsrfToken.php )

In the handle method you can check:

public function handle($request, Closure $next)
{
    if ( ! $request->is('api/*'))
    {
        return parent::handle($request, $next);
    }

    return $next($request);
}

Please sign in or create an account to participate in this conversation.