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
[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!
Another reply since I forgot to subscribe on the first one.
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.
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.
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.
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.
I temporarily also commented out the middleware. But this option isn't viable for longterm.
Same problem here, any good solutions yet?
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.
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.
This post is redundant with this one.
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);
}
Btw it's not so hard to send token with Ajax...
@bestmomo I agree it's easy to send the token with ajax. You should do it. The problem is with api calls.
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);
}
@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.
@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/' ]; }
@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
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!
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/*'
];
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?
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.
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.