Hi,
I’m working on a new Project (CakePHP 4.0.2) where I want to enable additional routes in order to provide JSON based access to some controllers using a specfic routing scope (/api).
This works fine when I call the controllers in the browser (both scopes), but not when I try to submit POST requests via curl - This always triggers a forbidden (403) with
"message": "Missing CSRF token cookie"
Obviously the CSRF middleware is attached though I’m accessing the controllers through a different scope (as described in the comments of the template).
It seems to me this is caused by the RouteBuilder object which is the same for both scopes (Though I thought that a different scope would allow me to define access without using any additional middleware).
While digging through the cake-sources in order to understand the problem I’ve found that the routes.php is read through the RoutingMiddleware that is attached in Application.php, but I don’t see any point in code to hook into.
I’m pretty sure I must be missing something, so can you please check my routes.php and tell me where I’m wrong?
<?php
/**
* Routes configuration.
*
* In this file, you set up routes to your controllers and their actions.
* Routes are very important mechanism that allows you to freely connect
* different URLs to chosen controllers and their actions (functions).
*
* It's loaded within the context of `Application::routes()` method which
* receives a `RouteBuilder` instance `$routes` as method argument.
*
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
/*
* The default class to use for all routes
*
* The following route classes are supplied with CakePHP and are appropriate
* to set as the default:
*
* - Route
* - InflectedRoute
* - DashedRoute
*
* If no call is made to `Router::defaultRouteClass()`, the class used is
* `Route` (`Cake\Routing\Route\Route`)
*
* Note that `Route` does not do any inflections on URLs which will result in
* inconsistently cased URLs when used with `:plugin`, `:controller` and
* `:action` markers.
*/
/** @var \Cake\Routing\RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);
$routes->scope('/', function (RouteBuilder $builder) {
// Register scoped middleware for in scopes.
$builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([
'httpOnly' => true,
]));
/*
* Apply a middleware to the current route scope.
* Requires middleware to be registered through `Application::routes()` with `registerMiddleware()`
*/
$builder->applyMiddleware('csrf');
/*
* Here, we are connecting '/' (base path) to a controller called 'Pages',
* its action called 'display', and we pass a param to select the view file
* to use (in this case, templates/Pages/home.php)...
*/
$builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
/*
* ...and connect the rest of 'Pages' controller's URLs.
*/
$builder->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
/*
* Connect catchall routes for all controllers.
*
* The `fallbacks` method is a shortcut for
*
* ```
* $builder->connect('/:controller', ['action' => 'index']);
* $builder->connect('/:controller/:action/*', []);
* ```
*
* You can remove these routes once you've connected the
* routes you want in your application.
*/
$builder->fallbacks();
});
/*
* If you need a different set of middleware or none at all,
* open new scope and define routes there.
*
* ```
* $routes->scope('/api', function (RouteBuilder $builder) {
* // No $builder->applyMiddleware() here.
* // Connect API actions here.
* });
* ```
*/
$routes->scope('/api', function (RouteBuilder $builder) {
$builder->setExtensions(['json']);
$builder->resources('MyResource1');
$builder->resources('MyResource2');
$builder->resources('MyResource3');
});
Thank you very much for your time and any hint about what is wrong here!