Magento 2.3 upgrade breaks HTTP POST requests to custom module endpoint
UPDATE: I changed the accepted answer to the one from @AnanthMage2 as it follows Magento's coding practices
Found the solution, your controller must implement CsrfAwareActionInterface and 2 of its methods:
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Request\InvalidRequestException;
class MyController extends \Magento\Framework\App\Action\Action implements CsrfAwareActionInterface
{
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
{
return null;
}
public function validateForCsrf(RequestInterface $request): ?bool
{
return true;
}
}
This solves the problem, but is also backwards incompatible, i.e. your module will now not work on Magento 2.2 and earlier. To make it backwards compatible, something like the following is needed:
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Request\InvalidRequestException;
if (interface_exists("Magento\Framework\App\CsrfAwareActionInterface"))
include __DIR__ . "/MyController.m230.php";
else
include __DIR__ . "/MyController.m220.php";
Where you would have the full and correct class declaration in each of the two files.
Please check more generous solution that does not change core functionality, you can use around plugin on Validate function of Magento\Framework\App\Request\CsrfValidator class
This implementation does not break the core functionality of Magento 2.1/2.2/2.3 versions.
di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\App\Request\CsrfValidator">
<plugin name="csrf_validator_skip" type="Module\Vendor\Plugin\CsrfValidatorSkip" />
</type>
</config>
CsrfValidatorSkip.php
<?php
namespace Module\Vendor\Plugin;
class CsrfValidatorSkip
{
/**
* @param \Magento\Framework\App\Request\CsrfValidator $subject
* @param \Closure $proceed
* @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\App\ActionInterface $action
*/
public function aroundValidate(
$subject,
\Closure $proceed,
$request,
$action
) {
if ($request->getModuleName() == 'Your_Module_frontName_Here') {
return; // Skip CSRF check
}
$proceed($request, $action); // Proceed Magento 2 core functionalities
}
}
Please star my Gist page at https://gist.github.com/ananth-iyer/59ecfabcbca73d6c2e3eeb986ed2f3c4 to encourage.
Implement CsrfAwareActionInterface is a solution, but it makes the code not compatible with Magento < 2.3
Here is a trick (injecting the Key to the request on the Action) that is compatible with Magento 2.X
Put it in the constructor of the Action.
// CsrfAwareAction Magento2.3 compatibility
if (interface_exists("\Magento\Framework\App\CsrfAwareActionInterface")) {
$request = $this->getRequest();
if ($request instanceof HttpRequest && $request->isPost() && empty($request->getParam('form_key'))) {
$formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class);
$request->setParam('form_key', $formKey->getFormKey());
}
}