Table of Contents

  1. Ext: sg_captcha

Ext: sg_captcha

sgalinski logo

License: GNU GPL, Version 2

Repository: https://gitlab.sgalinski.de/typo3/sg_captcha

Please report bugs here: https://gitlab.sgalinski.de/typo3/sg_captcha/-/issues

Overview

sg_captcha provides central ALTCHA and Friendly Captcha integration for TYPO3 14. It supplies server-side verification, an uncached ALTCHA challenge endpoint and Fluid widgets for extensions that protect public forms.

Requirements

  • PHP 8.3 or newer
  • TYPO3 14.3
  • sgalinski/sg-apicore 3.1 or newer

Installation

Install the extension with Composer and activate it in TYPO3. Its TypoScript is registered automatically. Install frontend dependencies in Resources/Public before packaging the extension so both provider assets are available to the public web directory.

Configuration

Configure CAPTCHA centrally in the TYPO3 Extension Configuration for sg_captcha. enabled controls protection for all consumers and provider selects either altcha or friendlycaptcha. Configure the Friendly Captcha site and API keys in the same Extension Configuration when that provider is selected.

ALTCHA v3

ALTCHA uses the v3 widget and the v2 server protocol. Its default is the memory-hard ARGON2ID algorithm (cost = 3, memoryCost = 65536 KiB, parallelism = 1). The widget uses one worker to avoid multiplying the memory requirement on client devices. PHP must provide ext-sodium, which is included in supported PHP distributions.

The widget, its Argon2id worker registration and form validation are registered as ordered ES modules through TYPO3's AssetCollector. Do not add the ALTCHA library separately in a site package: the local altchaConfiguration.js module must run between the v3 widget and validation module so the memory-hard worker is available before a challenge is loaded.

To use ALTCHA v3, create the tx_sgcaptcha_used_solution table and its indexes with the TYPO3 Database Analyzer. Configure the Table garbage collection Scheduler task for tx_sgcaptcha_used_solution, using expires_at as the expiry field. It removes the expired replay-protection fingerprints.

Challenges expire after five minutes. A successfully verified solution is stored only as a SHA-256 fingerprint until its signed expiry time and can be submitted once. No CAPTCHA payload or personal data is persisted. After changing ALTCHA settings, clear TYPO3 caches and test every protected form in supported browsers.

Legacy Friendly Captcha settings

After updating, run Migrate legacy Friendly Captcha settings to sg_captcha in the Install Tool's Upgrade module. It copies non-empty SITE_WEBSITE_BASE_FRIENDLYCAPTCHASITEKEY and SITE_WEBSITE_BASE_FRIENDLYCAPTCHAAPIKEY values into the central Extension Configuration without overwriting values that are already configured there.

Usage

The shared ALTCHA challenge endpoint is:

GET /api/public/v1/captchas/altcha/challenge

Fluid templates can render the widget with <sc:captchaWidget name="captcha" id="contact-captcha" language="en" /> after declaring the SGalinski/SgCaptcha/ViewHelpers namespace. Server-side code must use CaptchaVerifier; invalid or missing solutions must block the protected action.

The ALTCHA widget automatically registers the provider asset and the central client-side validation module through TYPO3's AssetCollector. The module prevents submission before a challenge is verified and displays the localized validation message supplied by the widget. Consumers that render a raw <altcha-widget> must include EXT:sg_captcha/Resources/Public/JavaScript/altchaValidation.js as a module and set its data-sg-captcha-validation-message attribute.

Using the PHP APIs from another extension

Declare sgalinski/sg-captcha as a Composer dependency of the consuming extension. Use constructor injection; do not implement provider-specific verification or read provider credentials outside sg_captcha.

For a regular controller or API endpoint, inject CaptchaVerifier and pass the PSR-7 request to verifyRequest(). The verifier resolves the correct field name for the centrally selected provider and accepts the request when CAPTCHA protection is globally disabled.

use Psr\Http\Message\ServerRequestInterface;
use SGalinski\SgCaptcha\Service\CaptchaVerifier;

public function __construct(private readonly CaptchaVerifier $captchaVerifier) {
}

public function create(ServerRequestInterface $request): void {
	if (!$this->captchaVerifier->verifyRequest($request)) {
		// Add a localized validation error and stop processing.
		return;
	}

	// Persist the protected data.
}

If a TYPO3 Form element must validate the CAPTCHA, add FormCaptchaValidator to the Captcha element. The validator reads the current request, delegates to the same central verifier and adds the frontend.captcha.validation error to the form when verification fails.

use SGalinski\SgCaptcha\FormElements\Captcha;
use SGalinski\SgCaptcha\Validation\FormCaptchaValidator;
use TYPO3\CMS\Core\Utility\GeneralUtility;

$captcha = GeneralUtility::makeInstance(Captcha::class);
$captcha->addValidator(GeneralUtility::makeInstance(FormCaptchaValidator::class));
$page->addElement($captcha);

For custom request structures, inject CaptchaSolutionResolver alongside CaptchaVerifier, call resolve($request) and pass the returned solution to verify($solution). In normal HTML forms, prefer verifyRequest() so nested TYPO3 Form argument names are handled consistently.

Testing

Run composer ecs vendor/sgalinski/sg-captcha, composer phpstan vendor/sgalinski/sg-captcha and composer phpunit vendor/sgalinski/sg-captcha.

Upgrade Notes

Run the relevant Upgrade Wizards from the Install Tool after installing a new version. The legacy Friendly Captcha settings migration is described above.