Skip to content

CAPTCHA v26.7+

The API Platform does not bundle any CAPTCHA provider. Instead, it exposes two events that any captcha module can observe, making the system completely provider-agnostic.

How it works

Configuration, endpoints that need to advertise CAPTCHA settings to a frontend (e.g. GET /contact/config) read from store config and/or the api_captcha_config event. The exact fields exposed depend on the endpoint; for /contact/config they are flat: captchaProvider, captchaSiteKey, enabled. Other endpoints (or third-party modules calling Mage::helper('apiplatform')->getCaptchaConfig()) get the open key/value bag populated by the event.

The frontend uses this to load the right widget (Turnstile, reCAPTCHA, etc.) and obtain a token.

Verification, on form submission, include the solved token as captchaToken in the request body. The API dispatches api_verify_captcha and the active module verifies it.

Events

Event Purpose Observer parameters
api_captcha_config Describe the active provider to the frontend config (DataObject, set enabled, provider, and any provider-specific fields like challengeUrl or siteKey)
api_verify_captcha Verify a submitted token result (DataObject, set verified to false and error to a message string to reject), data (array, the full request body, token is in captchaToken)

Helper methods

Any API controller or processor can verify captcha tokens via the ApiPlatform helper:

/** @var Maho_ApiPlatform_Helper_Data $helper */
$helper = Mage::helper('apiplatform');

// Get config for the frontend
$captchaConfig = $helper->getCaptchaConfig();

// Verify a token, returns null on success, error message on failure
$error = $helper->verifyCaptcha($requestData);
if ($error !== null) {
    // reject the request
}

Built-in: Altcha (Maho_Captcha)

The native Maho_Captcha module observes both events out of the box using Altcha, a self-hosted, privacy-friendly proof-of-work challenge that requires no third-party API calls.

Third-party providers

A Turnstile or reCAPTCHA module just needs to observe the same two events. For example:

<config>
    <api>
        <events>
            <api_captcha_config>
                <observers>
                    <my_turnstile>
                        <class>my_turnstile/observer</class>
                        <method>getCaptchaConfig</method>
                    </my_turnstile>
                </observers>
            </api_captcha_config>
            <api_verify_captcha>
                <observers>
                    <my_turnstile>
                        <class>my_turnstile/observer</class>
                        <method>verifyCaptcha</method>
                    </my_turnstile>
                </observers>
            </api_verify_captcha>
        </events>
    </api>
</config>
class My_Turnstile_Model_Observer
{
    public function getCaptchaConfig(\Maho\Event\Observer $observer): void
    {
        $config = $observer->getEvent()->getConfig();
        $config->setEnabled(true);
        $config->setProvider('turnstile');
        $config->setSiteKey(Mage::getStoreConfig('my_turnstile/general/site_key'));
    }

    public function verifyCaptcha(\Maho\Event\Observer $observer): void
    {
        $data = $observer->getEvent()->getData('data');
        $token = $data['captchaToken'] ?? '';
        $result = $observer->getEvent()->getResult();

        // Call Turnstile verify API...
        if (!$this->verifyToken($token)) {
            $result->setVerified(false);
            $result->setError('CAPTCHA verification failed.');
        }
    }
}