Self-hosted Convertigo library for creating and verifying ALTCHA v2 proof-of-work challenges with the official Java implementation and reusable NGX widget.
ALTCHA is a strong privacy-friendly alternative to SaaS CAPTCHA services. Once this project is deployed, challenge creation, browser proof-of-work, payload verification, action binding, expiration checks, and replay detection are handled entirely by the Convertigo application and the browser.
No request is sent to an external CAPTCHA provider at runtime. There is no third-party CAPTCHA account, API key, remote scoring service, tracking cookie, or external availability dependency. The solution is therefore 100% autonomous and self-hosted at runtime. The official ALTCHA client is bundled with the NGX application and the official Java library runs inside the Convertigo Engine.
altcha_createChallengeselects a cryptographically random counter in the configured range, embeds optional business data such as an action, adds an expiration time, and signs the challenge with HMAC.- The ALTCHA widget solves the challenge locally in the browser. It tries counters and derives a key for each candidate until it finds the expected signed key prefix.
- The browser submits the resulting Base64 payload with the business form.
- The business sequence calls the private
altcha_verifyPayloadsequence. The server verifies the challenge signature, solution, expiration, expected action, and replay status before accepting the operation. - With the independent key-signature secret used by this project, successful deterministic solutions can be verified efficiently without repeating the complete browser workload on the server.
The client-side “Verified” state is only a user-interface signal. A business operation must always send the payload to altcha_verifyPayload or to a server sequence such as altcha_demoSubmit that calls it internally.
With the default PBKDF2/SHA-256 algorithm, lib_Captcha.altcha.cost is the PBKDF2 iteration count used for each candidate counter. The default cost is 5000.
The counter range controls how many candidate values the browser is likely to test. This project chooses a random target counter in the half-open interval:
[counter.min, counter.max)
With the defaults 5000 and 10000, the browser typically performs between approximately 5,000 and 10,000 candidate derivations. The effective client workload is therefore influenced by both:
- the KDF cost per candidate;
- the number of candidate counters that must be tested.
Increasing cost, counter.min, or counter.max increases resistance to bulk automated solving, but it also increases CPU usage, battery consumption, and verification latency on legitimate client devices. More Web Workers can reduce wall-clock time by distributing the search, but they do not remove the total computational work. Tune these values using representative mobile and desktop devices rather than increasing them blindly.
For PBKDF2, the rough work factor is proportional to:
PBKDF2 iterations per candidate × number of attempted counters
The configured limits are validated when a challenge is created. The defaults provide a development-friendly baseline and should be performance-tested for each production audience.
ALTCHA is a proof-of-work CAPTCHA, not a proof of human identity. A successful solution proves that a client received an authentic challenge, performed the required computation, and returned a valid result before expiration. It does not prove that the client is a human, that one solution corresponds to one physical person, or that the submitted business data are trustworthy.
Automated software can still:
- request challenges from the public challenge endpoint;
- run the same proof-of-work algorithm in a headless browser or custom client;
- use additional CPU resources or parallel workers;
- pay humans or external solving farms to complete challenges;
- create many independent valid challenges unless other controls limit the request rate.
The cost and counter range increase the economic and computational price of automation; they do not make automation impossible. Replay protection prevents reuse of the same accepted payload, but it does not prevent a bot from solving a fresh challenge for every request.
The checkbox and the client-side “Verified” state are user-experience elements, not a security boundary. Only server-side verification is authoritative. The self-hosted ALTCHA mode used by this library does not provide behavioral risk scoring, device reputation, identity verification, or a guarantee that a mouse click came from a human.
For sensitive operations, use ALTCHA as one layer in a broader abuse-prevention strategy:
- rate-limit challenge creation and protected business endpoints;
- bind every challenge to the intended business
action; - require authentication, email confirmation, or multi-factor authentication when appropriate;
- validate all business fields and apply domain-specific fraud rules;
- add privacy-respecting honeypots, velocity controls, quotas, or anomaly detection;
- monitor rejection, replay, and request-volume patterns;
- increase friction progressively instead of imposing an excessive proof-of-work cost on every legitimate user.
This limitation is not specific to ALTCHA: no checkbox CAPTCHA can mathematically prove humanity. ALTCHA is valuable because it provides a transparent, privacy-friendly and autonomous way to raise the cost of automated abuse without depending on a third-party SaaS service.
A valid proof-of-work payload remains cryptographically valid until its challenge expires. Without replay protection, a bot could capture one valid payload and submit it repeatedly during that validity period.
altcha_verifyPayload enables replay protection by default through preventReplay=true. After all cryptographic, expiration, and action checks succeed, the verifier atomically records the signed challenge identifier as consumed. The first submission is accepted; later submissions using the same payload are rejected with:
{
"verified": false,
"replayed": true,
"error": "replayed"
}Consumed identifiers are retained until the challenge expiration time and expired entries are cleaned from the registry. Recording happens only after successful verification, so malformed or invalid submissions cannot consume a legitimate challenge.
The built-in replay registry is stored in a thread-safe, node-local in-memory map and is bounded to protect the engine. This is fully autonomous for a single Convertigo Engine instance. In a multi-node cluster, use a shared atomic store such as Redis or a database, or enforce node affinity, so that the same payload cannot be accepted once by each node. Restarting an engine clears its in-memory replay registry, so short challenge expiration remains important.
Replay protection complements, but does not replace:
- short challenge expiration;
- binding challenges to an
action; - rate limiting on public challenge and business endpoints;
- server-side validation of the complete business request.
altcha_createChallenge: public challenge endpoint used by the widget.altcha_verifyPayload: private server-side verifier for signature, solution, expiration, expected action, and replay status.altcha_demoSubmit: demonstration business endpoint that calls the private verifier and returns a stable business response.
| Symbol | Required | Default | Description |
|---|---|---|---|
lib_Captcha.altcha.hmac.secret |
Yes in production | empty | Secret used to sign challenges. Use a random value containing at least 16 characters. |
lib_Captcha.altcha.key.secret |
Yes in production | empty | Independent secret used to sign derived keys and enable efficient deterministic verification. Use a random value containing at least 16 characters. |
lib_Captcha.altcha.algorithm |
No | PBKDF2/SHA-256 |
Key-derivation algorithm used by the challenge. |
lib_Captcha.altcha.cost |
No | 5000 |
Algorithm-specific cost; for PBKDF2 this is the iteration count for every candidate counter. |
lib_Captcha.altcha.counter.min |
No | 5000 |
Inclusive minimum random target counter. |
lib_Captcha.altcha.counter.max |
No | 10000 |
Exclusive maximum random target counter. |
lib_Captcha.altcha.expires.seconds |
No | 300 |
Challenge validity period in seconds. |
Symbols ending in .secret are masked by Convertigo. When the two secrets are not configured, the library generates temporary values suitable for development only. These values are lost when the engine restarts and are not shared between cluster nodes. Configure stable secrets in every production environment and use identical secrets on every node that must validate the same challenges.
Symbols are resolved directly in the JavaScript steps using Convertigo native symbol substitution syntax.
For more technical informations : documentation
-
In your Convertigo Studio click on
to import a project in the treeview -
In the import wizard
paste the text below into the
Project remote URLfield:Usage Click the copy button at the end of the line To contribute lib_Captcha=https://github.com/convertigo/lib_Captcha.git:branch=masterTo simply use lib_Captcha=https://github.com/convertigo/lib_Captcha/archive/master.zip -
Click the
Finishbutton. This will automatically import the lib_Captcha project
Describes the mobile application global properties
Reusable ALTCHA client widget for Convertigo NGX applications. Wraps the official altcha Web Component and exposes configurable challenge, presentation, localization, automation, and runtime options. The Verified, StateChanged, and Expired outputs allow host applications to react to widget events.
variables
| name | comment |
|---|---|
| action | Optional action bound to the challenge. The value is appended to the challenge URL and must match expectedAction during server-side verification. |
| auto | Automatic verification trigger: 'off', 'onfocus', 'onload', or 'onsubmit'. |
| challengeUrl | Optional absolute challenge URL. When empty, the component derives the portable lib_Captcha sequence URL from the public Convertigo SDK endpoint. |
| configuration | Additional ALTCHA configuration object. Explicit component variables override properties with the same name. |
| debug | Enables ALTCHA client-side debug logging when true. |
| display | Widget layout: 'standard', 'bar', 'floating', 'overlay', or 'invisible'. |
| hideFooter | Hides the ALTCHA attribution footer when true. |
| hideLogo | Hides the ALTCHA logo when true. |
| language | ISO language code used by the widget. English is bundled by default. |
| minDuration | Minimum verification duration in milliseconds. |
| name | Name of the hidden form field that receives the verified ALTCHA payload. |
| theme | Widget theme name, normally 'default' or 'dark'. |
| timeout | Maximum verification duration in milliseconds. |
| type | Interaction style: 'checkbox', 'switch', or 'native'. |
| validationMessage | HTML5 validation message shown while verification is incomplete. |
| workers | Number of Web Workers used for proof-of-work computation. |
events
| name | comment |
|---|---|
| Expired | Emits the ALTCHA expired event detail when the current challenge expires. |
| StateChanged | Emits the ALTCHA statechange event detail whenever the widget state changes. |
| Verified | Emits the ALTCHA verified event detail, including the generated payload. |
