geekybones / fraud-defense-bundle
Symfony bundle for Google reCAPTCHA Enterprise (forms, validation, score and checkbox widgets)
Package info
github.com/geekybones/fraud-defense-bundle
Type:symfony-bundle
pkg:composer/geekybones/fraud-defense-bundle
Requires
- php: ^8.2
- google/cloud-recaptcha-enterprise: ^2.0
- psr/log: ^3.0
- symfony/config: ^7.0|^8.0
- symfony/dependency-injection: ^7.0|^8.0
- symfony/form: ^7.0|^8.0
- symfony/http-foundation: ^7.0|^8.0
- symfony/http-kernel: ^7.0|^8.0
- twig/twig: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^11.0|^12.0|^13.0
- rector/rector: ^2.0
- symfony/twig-bridge: ^7.0
- symfony/yaml: ^7.0|^8.0
README
Symfony integration for Google reCAPTCHA Enterprise with support for standard bot protection, Transaction Defense, and SMS toll-fraud Defense. By GeekyBones.
| Package | geekybones/fraud-defense-bundle |
| PHP | ^8.2 |
| Symfony | ^7.0 or ^8.0 |
| License | MIT |
Installation
composer require geekybones/fraud-defense-bundle
If Symfony Flex did not register the bundle automatically, add it to config/bundles.php:
GeekyBones\FraudDefenseBundle\FraudDefenseBundle::class => ['all' => true],
Google Cloud setup
- Enable the reCAPTCHA Enterprise API in your GCP project.
- Create one or more site keys for your domain (score key for invisible checks, checkbox key for the "I'm not a robot" widget).
- Create an API key restricted to the reCAPTCHA Enterprise API.
For Transaction Defense and SMS Defense, additional console steps are required — see their dedicated guides.
Configuration
Add environment variables:
FRAUD_DEFENSE_PROJECT_ID=your-gcp-project-id FRAUD_DEFENSE_API_KEY=your-api-key FRAUD_DEFENSE_SITE_KEY=your-score-site-key # FRAUD_DEFENSE_CHECKBOX_SITE_KEY=your-checkbox-site-key # only if using checkbox widget
Create config/packages/fraud_defense.yaml:
fraud_defense: project_id: '%env(FRAUD_DEFENSE_PROJECT_ID)%' api_key: '%env(FRAUD_DEFENSE_API_KEY)%' site_key: '%env(FRAUD_DEFENSE_SITE_KEY)%' min_score: 0.5
Standard reCAPTCHA (RecaptchaType) works with this minimal config. Enable transaction_defense or sms_defense only when you need those flows.
See configuration.md for all options.
Usage
Standard form protection
use GeekyBones\FraudDefenseBundle\Form\RecaptchaType; $builder->add('captcha', RecaptchaType::class, [ 'action' => 'login', ]);
{{ form_row(form.captcha) }}
Validation runs automatically on form submit. No controller changes needed.
Programmatic
Inject the interface and call assess() directly — useful in APIs and controllers without forms:
use GeekyBones\FraudDefenseBundle\Defense\Contract\RecaptchaAssessmentInterface; use GeekyBones\FraudDefenseBundle\Defense\DefenseAssessmentException; public function __construct( private readonly RecaptchaAssessmentInterface $recaptcha, ) {} try { $result = $this->recaptcha->assess( token: $request->request->get('recaptcha_token'), action: 'login', ); } catch (DefenseAssessmentException $e) { // API error, invalid/expired token, or incomplete response } if (!$result->hasPassed()) { // score too low, action mismatch, or hostname mismatch }
Form types
| Form type | When to use | Requires |
|---|---|---|
RecaptchaType |
Login, registration, contact — bot detection | Default config |
TransactionRecaptchaType |
Checkout, payment — fraud risk scoring | transaction_defense.enabled: true |
SmsRecaptchaType |
SMS OTP — toll-fraud detection | sms_defense.enabled: true |
All three share the same Twig widget ({{ form_row(form.captcha) }}).
Documentation
| Guide | Contents |
|---|---|
| configuration.md | All YAML options, environment variables, per-case examples |
| recaptcha.md | Standard reCAPTCHA: form setup, script loading, programmatic usage |
| transaction-defense.md | Transaction Defense: GCP setup, form, context reference, troubleshooting |
| sms-defense.md | SMS Defense: GCP setup, form, programmatic usage |
| architecture.md | Internal code structure and request flow |