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

alexleonard's avatar

[L5] Avoiding CSRF middleware on API POST routes

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!

0 likes
24 replies
coopers98's avatar

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

1 like
coopers98's avatar

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

alexleonard's avatar

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's avatar

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's avatar

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.

3 likes
alexleonard's avatar

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.

1 like
nWidart's avatar

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

trevorg's avatar

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.

1 like
mglinski's avatar

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.

nWidart's avatar

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's avatar

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

pmall's avatar

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

6 likes
pmall's avatar

@billmn More cleaner way :

# app/Http/Kernel.php :

    /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
        'Illuminate\Cookie\Middleware\EncryptCookies',
        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
        'Illuminate\Session\Middleware\StartSession',
        'Illuminate\View\Middleware\ShareErrorsFromSession',
        // 'App\Http\Middleware\VerifyCsrfToken', // Erase this
    ];
    /**
     * The application's route middleware.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => 'App\Http\Middleware\Authenticate',
        'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
        'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
        'csrf' => 'App\Http\Middleware\VerifyCsrfToken',
    ];

Then in route.php :

// List of api routes

$router->group(['middleware' => 'csrf'], function($router)
{
  // CSRF protected routes.
});

But again, ajax calls should be csrf protected. This method above is cool for api calls from external places.

1 like
Mashauri's avatar

@billmn post gave an idea, all you have to do just open this file app/Http/Middleware/VerifyCsrfToken.php and add 'api/*' in protected $except array. Works for me and is clean way to exception routes.

use Closure; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier { /** * The URIs that should be excluded from CSRF verification. * * @var array / protected $except = [ 'api/' ]; }

2 likes
billmn's avatar

@Mashauri Yep but my post refers to Laravel 5.0 and not 5.1

Now that I have upgraded my application to L 5.1 I've used the 'except' property and works fine

arielcalcano's avatar

After hours of research, I could fix the problem by simply adding the domain in: config/session.php

"Session Cookie Domain"

'domain' => 'your-app-domain'

It doesn't matter if the session driver is "database or other"

Greetings!

criste_nicu's avatar

in Http/Middleware/VerifyCsrfToken.php you have an array called $except. Just add your api uri.

    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'api/*'
    ];
12 likes
drodriguez's avatar

Hi!

I was implementing this by grouping my API routes with the prefix 'api' and excluding it in the $except array as @criste_nicu said.

But I was wondering how to do it if I change my api call routes from a prefix to a subdomain like api.mydomain.com?

juandmegon's avatar

A RESTful API should be stateless, it means that it is not neccessary to keep the state through requests (sessions) in this way the CSRF verification is not completely necessary. To "disable" the sesssion, just go to the .env file and there change SESSION_DRIVER to array: SESSION_DRIVER=array

In this way it is not possible that someone take advantage of a stored sessions (CSRF).

Then you can just disable the CSRF middleware, commenting the respective line in the kernel.php file.

Aditionaly is a very good idea add some validation mechanism like basic auth (at least), or preferibly OAuth2 or JWT.

Hope many of you found this helpful.

1 like
murph133's avatar

Thank you @billmn.

I had a problem integrating a GoCardless API into Laravel 5.4.

My server was responding with a 500 internal server error.

Adding the uri of my webhook to /Middleware/VerifyCsrfToken.php solved the problem.

Please or to participate in this conversation.