Can not disable CSRF for only 1 action in CakePHP 5.0.5?

I am using CakePHP 5.0.5 to write an App that connect to Strava and get running activities for users.

Strava require a webhook so that it can push update event of user activity to my app. That is why I have to disable CSRF for that webhook action.

My webhook action is:

public function webhook()
    {   
        // Event call back
        if ($this->request->is('post')) {
            $object_type = $this->request->getQuery('object_type');

            if (!is_null($object_type)){
               //do something later
            }

            $this->set('result', 'OK');
            $this->viewBuilder()->setOption('serialize', ['result']);
            return;
        }
        
        // Webhook subscription validation
        if ($this->request->is('get')) {
            $subcribe_result = $this->request->getQuery('hub_challenge');

            if (!is_null($subcribe_result)){
            $this->set('hub.challenge', $subcribe_result);
            $this->viewBuilder()->setOption('serialize', ['hub.challenge']);
            return;
            }
        }
    }

I also disable CSRF for that webhook action like this:

public function initialize(): void
    {
        parent::initialize();
        //$this->loadComponent('RequestHandler');
        $this->Authentication->allowUnauthenticated(['webhook', 'webhook.json']);

        $this->loadComponent('Csrf');

    }

    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        parent::beforeFilter($event);
        
        // Check if the current action is the one for which you want to disable CSRF protection
        if (($this->getRequest()->getParam('action') === 'webhook.json') || ($this->getRequest()->getParam('action') === 'webhook')) {
            $this->getEventManager()->off($this->Csrf);
        }
    }

I also read Documentation for CakePHP 5, only find solution to disable CSRF for all actions which has prefix of something (“API”) in example below:

$csrf = new CsrfProtectionMiddleware();

    // Token check will be skipped when callback returns `true`.
    $csrf->skipCheckCallback(function ($request) {
        // Skip token check for API URLs.
        if ($request->getParam('prefix') === 'Api') {
            return true;
        }
    });

How do I disable CSRF for only 1 specific action of a specific controller ?

In your src/Application.php you can adjust the csrf middleware object before its enqueued in the middlewarequeue.

$csrf = new CsrfProtectionMiddleware([
    'httponly' => true,
]);
$csrf->skipCheckCallback(function (ServerRequest $request) {
    if (
        $request->getParam('controller') === 'MyController' &&
        $request->getParam('action') === 'myAction'
    ) {
        return true;
    }

    return false;
});

$middlewareQueue
    // all the other middlewares
   ->add($csrf);
1 Like

Thank you Mr. KevinPfeifer,

It works like a charm. You save my day.