if you didn't read the section above on what CAPTCHA_init does, you should

the cliffnotes are this though:

$self= a page object that contains a context object with access to the session and libapreq functions
'registration'= the name of the page used in creating a public_key seed ( this way register and confirm pages don't have the same captcha )
1= an override flag, that forces the captcha object to be reset, as sometimes we cache objects

in this example, the captcha generator is in a central location -- /service/captcha/ -- so we supply the section name as a query arg. if the captcha generator were locked into a page, then you could just hardcode the section name

There is a single constructer that 'forks' into 2 separate init routines based on an argument to new().

Both arguments create a new KeyManager instance before they fork.

The type='new' routine immediately calls the KeyManager method generate_publickey ( which could conceivably be a little resource intensive, if you've created a module that hits a db to check for collisions). The fork was an obvious solution to split unnecessary calls out for performance optimization (ie: only run what you need )

The type='existing' routine automatically validates the construction arguments via the KeyManger method validate_publickey, which is unnecessary for new captchas.

Originally there was a single 'new', and from that you could call either 'new()' or 'existing()' -- but more people like 1 line of code.

That depends on how the KeyManager class you specify uses the site_secret to validate the key (which is why site_secret is not required in the base class , it can be an empty string ). A DB backed key does not need the sitesecret for validation. A logic backed key needs all the construction args to validate.

I think there is some confusion in this tutorial because i do 2 things that are a little odd:

a- i run through the captcha generator to pull a new valid key, this way i can use a new example and have a key validate
b- i run through the captcha validator while i can 'guess' an obviously wrong answer. The way the system is structured, a solution is only provided when you try to validate the captcha. That is because you might want to 'Render' an existing sound/image captcha which is completely isolated from Validating it. By purposefully solving it wrong, the routine that sets up the correct user_response is run.

To display a CAPTCHA, you just create a new object and call the render method , passing in a challenge class and render class. You can call the render method as often as you'd like. Currently, the module will transparently validate the key in order to render the captcha.

create a KeyManager subclass, which creates a key and stores it to the db and does the validation
you might be interested in L<Authen::PluggableCaptcha::KeyManagerDB>, which is a db backed keymanager class

Good question. expire_publickey is a method of the captcha and keymanager classes. expire it in your page logic, or tell the base class to tell the manager to expire it. but all that code is up to you.

public_key= sprintf "%s:%s" , md5( time , site_secret , seed ) , time
time= temporal component that lets a captcha work for only a 5 minute window. note that is outside of, and inside of, the hash. this makes the time realistically unspoofably
site_secret= non-random seed unique to website to keep spammers from spoofing captcha
seed= something unique to build this captcha
in my setup:
$seed= $url . $session{'id'}
That makes sure that only 1 captcha is made for a certain URL and a certain session_id ( locked to that time - since the time is used to create the public key, something 1 second later or earlier would be different )
The drawback is that anyone with the same session_id (which can be spoofed / hijacked) can use that same captcha url for the time window
If you're comfortable storing session data, this might be better for you:
$seed= $url . $session{'id'} . $session{'captchas_solved'}
Where $session{'captchas_solved'} is undefined at first, but every time a captcha on that session is solved, session{captchas_solved}++

In the 'equation'/'transaction', the spammer has the URL , the session_id , and the time. BUT he does not know the site secret, or can control the session variables.

If you've got sessions involved on the page that supports captchas, that approach could probably handle things securely. It doesn't do a single-ticket expiry, but it pretty much makes it improbable to recreate the conditions to use a captcha more than once.

Create your own challege class and run a filter or create a function that only uses your subset of characters. This functionality was once provided in the system, but the list of discernable characters became so small it created captchas that were useless. Depending on the way you render your captcha, the list will change- text/image captchas can render iIl1 similiarly, a warped image will make z2 or 5s similar- or even 6G 9q.

Creating your own captcha challenge class, and using it, takes almost no code or time at all to implement (20 lines, maybe? and you can use existing challlenge as a template)

Authen::Pluggable captcha was designed so you can quickly and easily override default functionality like this.