artack/recaptcha-enterprise-bundle
Install the Bundle
composer require artack/recaptcha-enterprise-bundle:0.1.*
(Pin to 0.1.* to avoid breaking changes.)
Configure Environment Variables
Add these to .env:
ARTACK_GOOGLE_RECAPTCHA_ENABLED=true
ARTACK_GOOGLE_RECAPTCHA_SITE_KEY=your_site_key
ARTACK_GOOGLE_RECAPTCHA_PROJECT_ID=your_project_id
ARTACK_GOOGLE_RECAPTCHA_API_KEY=your_api_key
Create Config File
Generate config/packages/artack_recaptcha_enterprise.yaml (see README for template).
First Use Case: Add to a Form
use Artack\RecaptchaEnterpriseBundle\Form\RecaptchaEnterpriseType;
$builder->add('recaptchaToken', RecaptchaEnterpriseType::class, [
'action_name' => 'submit_form', // Required for validation
]);
Render the Form The bundle auto-loads Twig templates. No manual CSP nonce is needed unless using strict policies.
Form Integration
RecaptchaEnterpriseType to any form. The hidden token field is auto-generated.action_name to tie tokens to specific form submissions (e.g., 'contact', 'signup').
$builder->add('recaptchaToken', RecaptchaEnterpriseType::class, [
'action_name' => 'user_registration',
]);
Validation
RecaptchaEnterprise validator to fields or classes.
use Artack\RecaptchaEnterpriseBundle\Validator\RecaptchaEnterprise;
#[RecaptchaEnterprise(minScore: 0.9, actionName: 'admin_panel')]
class AdminFormType extends AbstractType { ... }
min_score in artack_recaptcha_enterprise.yaml (fallback for unconfigured constraints).Conditional Enforcement
when@dev:
artack_recaptcha_enterprise:
enabled: false
if (!$this->getUser()->isAdmin()) {
$builder->add('recaptchaToken', RecaptchaEnterpriseType::class);
}
CSP Integration
script_csp_nonce if using Content Security Policy:
$builder->add('recaptchaToken', RecaptchaEnterpriseType::class, [
'script_csp_nonce' => $this->getCspNonceGenerator()->generate(),
]);
unsafe-inline in CSP (not recommended for production).API-Only Forms
grecaptcha.enterprise.execute('SITE_KEY', {action: 'api_submit'})
.then(token => document.getElementById('recaptcha_token').value = token);
# config/validator/constraints.yaml
Artack\RecaptchaEnterpriseBundle\Validator\RecaptchaEnterprise:
message: 'reCAPTCHA score too low ({{ score }}). Please try again.'
$validator = $this->createMock(RecaptchaEnterpriseValidator::class);
$validator->method('validate')->willReturn(null); // Simulate success
$this->container->set(RecaptchaEnterpriseValidator::class, $validator);
Token Mismatch Errors
action_name in the form type must match the validator’s actionName.// Form type
'action_name' => 'login_form'
// Validator
new RecaptchaEnterprise(actionName: 'login_form')
Score Thresholds
min_score (0.5) may be too low for high-risk forms.artack_recaptcha_enterprise:
min_score: 0.9 # Strict for all forms
Dev Environment Leaks
enabled: false in dev may still expose site keys in templates.{% if app.environment == 'dev' %}
{# No reCAPTCHA script #}
{% else %}
{{ form_widget(form.recaptchaToken) }}
{% endif %}
Rate Limits
CSP Nonce Generation
CspNonceGenerator or a custom service:
$nonce = $this->cspNonceGenerator->generate();
Artack\RecaptchaEnterpriseBundle:
monolog:
handlers:
main:
level: debug
$event->getData()->get('recaptchaToken'); // In a form event listener
Custom Validators
Extend RecaptchaEnterpriseValidator to add logic (e.g., IP-based score adjustments):
class CustomRecaptchaValidator extends RecaptchaEnterpriseValidator {
public function validate($value, Constraint $constraint): void {
if ($this->isHighRiskIp($value)) {
$constraint->minScore = 0.95;
}
parent::validate($value, $constraint);
}
}
Event Listeners
Hook into RecaptchaEnterpriseEvent to modify requests/responses:
use Artack\RecaptchaEnterpriseBundle\Event\RecaptchaEnterpriseEvent;
$dispatcher->addListener(RecaptchaEnterpriseEvent::PRE_VALIDATE, function (RecaptchaEnterpriseEvent $event) {
$event->setCustomData(['user_id' => $this->getUser()->getId()]);
});
Twig Overrides Customize the token field template:
{# templates/artack_recaptcha_enterprise/recaptcha_enterprise.html.twig #}
<div class="custom-recaptcha">
{{ parent() }}
</div>
user_registration, password_reset) for analytics.defer:
<script src="https://www.gstatic.com/recaptcha/api.js?render=SITE_KEY" defer></script>
How can I help you explore Laravel packages today?