druidfi / symfony-altcha-bundle
Altcha CAPTCHA integration for Symfony — form type, validator, and self-hosted/Sentinel support
Package info
github.com/druidfi/symfony-altcha-bundle
Language:JavaScript
Type:symfony-bundle
pkg:composer/druidfi/symfony-altcha-bundle
Requires
- php: >=8.2
- altcha-org/altcha: ^2.0
- symfony/dependency-injection: ^7.0|^8.0
- symfony/form: ^7.0|^8.0
- symfony/framework-bundle: ^7.0|^8.0
- symfony/http-foundation: ^7.0|^8.0
- symfony/http-kernel: ^7.0|^8.0
- symfony/routing: ^7.0|^8.0
- symfony/validator: ^7.0|^8.0
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 13:43:07 UTC
README
Altcha is a privacy-friendly, self-hostable CAPTCHA. This integration supports both self-hosted (proof-of-work, no external calls) and Sentinel/cloud (server-side verification via Altcha's API) modes.
Files
| File | Purpose |
|---|---|
src/Service/AltchaService.php |
Core logic: create challenges, verify solutions |
src/Controller/AltchaChallengeController.php |
GET /altcha/challenge endpoint (self-hosted mode) |
src/Form/Type/AltchaType.php |
Symfony form type — renders the widget and applies validation |
src/Validator/AltchaValid.php |
Constraint attribute |
src/Validator/AltchaValidValidator.php |
Constraint validator — calls AltchaService::verify() |
templates/altcha_form.html.twig |
Twig block that renders the <altcha-widget> element |
public/js/altcha.js |
Vendored Altcha widget JS (used in self-hosted mode) |
public/js/altcha-i18n.js |
Finnish (fi) and Swedish (sv) translations for the widget |
Environment variables
All variables are defined in .env. Override them per environment in .env.local / .env.prod etc.
| Variable | Default | Description |
|---|---|---|
ALTCHA_HMAC_KEY |
dev-only-hmac-key-change-in-production |
HMAC secret for signing challenges. Must be changed in production. |
ALTCHA_ENABLED |
(empty) | Set to false or 0 to disable CAPTCHA validation entirely. Useful in test/dev environments. |
ALTCHA_COST |
50000 |
PBKDF2 iteration count for proof-of-work challenges. Higher = harder for bots, slower for users. |
ALTCHA_SENTINEL_URL |
(empty) | Set to enable Sentinel/cloud mode. Base challenge URL handed to the widget. |
ALTCHA_SENTINEL_VERIFY_URL |
(empty) | Optional override for the Sentinel verify endpoint. Derived from ALTCHA_SENTINEL_URL if omitted. |
ALTCHA_SENTINEL_API_KEY |
(empty) | API key appended to ALTCHA_SENTINEL_URL as ?apiKey=. Allows the URL and key to be stored as separate secrets. |
ALTCHA_SENTINEL_API_SECRET |
(empty) | API secret sent in the Sentinel verify request body. Distinct from the API key. |
ALTCHA_HIDE_FOOTER |
true |
Hide the "Powered by Altcha" footer in the widget. |
ALTCHA_HIDE_LOGO |
true |
Hide the Altcha logo in the widget. |
ALTCHA_SCRIPT_URL |
/js/altcha.js |
URL to the Altcha widget JS. Use /js/altcha.js for the vendored local copy or a CDN URL. |
ALTCHA_AUTO |
(empty) | Auto-solve mode: onload (invisible, solves on page load), onsubmit (solves on form submit), or empty for manual checkbox (default). |
ALTCHA_FLOATING |
(empty) | Set to true or 1 to show the widget as a floating badge instead of an inline element. |
Modes
Self-hosted (default)
All three ALTCHA_SENTINEL_* variables are empty. The widget fetches a challenge from /altcha/challenge, solves it client-side using proof-of-work (PBKDF2), and submits the solution in a hidden form field. The server verifies the HMAC signature locally — no external calls.
Sentinel / cloud
Set ALTCHA_SENTINEL_URL to your Sentinel challenge base URL (e.g. https://eu.altcha.org/api/v1/challenge). Set ALTCHA_SENTINEL_API_KEY to your API key — it will be appended as ?apiKey= automatically. This allows the URL and key to be stored as separate secrets in a vault. Alternatively, you can embed the key directly in ALTCHA_SENTINEL_URL and leave ALTCHA_SENTINEL_API_KEY empty.
ALTCHA_SENTINEL_VERIFY_URL is optional — if omitted, the verify URL is derived from ALTCHA_SENTINEL_URL by replacing the path with /api/v1/verify/signature.
ALTCHA_SENTINEL_API_SECRET is the API secret sent in the verify request body (secret field). It is separate from the API key.
Usage in a form
Add the field to any Symfony form class:
use Druidfi\AltchaSymfony\Form\Type\AltchaType; $builder->add('altcha', AltchaType::class);
The form type renders the widget via templates/altcha_form.html.twig and automatically attaches an AltchaValid constraint. No extra configuration is needed.
To show the floating badge style on a specific form, pass the floating option:
$builder->add('altcha', AltchaType::class, ['floating' => true]);
This overrides ALTCHA_FLOATING for that field only.
Translations
The Altcha widget bundles only English. public/js/altcha-i18n.js registers Finnish (fi) and Swedish (sv) translations via globalThis.$altcha?.i18n.set(), which the widget picks up reactively.
The widget resolves the display language in order: language attribute on <altcha-widget> → document.documentElement.lang → navigator.languages. The <html lang="{{ app.request.locale }}"> attribute in base.html.twig provides the locale automatically.
To add another language, append a translation object to altcha-i18n.js and call globalThis.$altcha?.i18n.set('<locale>', obj). See the existing fi/sv objects for the full list of required keys.
Updating the vendored JS
The file public/js/altcha.js is a vendored copy of the Altcha widget. To update it, replace it with the latest altcha.js from the Altcha releases or from npm (altcha package, dist/main/altcha.js), then set ALTCHA_SCRIPT_URL=/js/altcha.js.