Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Karser Recaptcha3 Bundle Laravel Package

karser/karser-recaptcha3-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require karser/karser-recaptcha3-bundle
    

    Enable the bundle in config/bundles.php:

    Karser\Recaptcha3Bundle\KarserRecaptcha3Bundle::class => ['all' => true],
    
  2. Configure Keys Add your Google reCAPTCHA v3 keys to .env:

    KARSER_RECAPTCHA_SITE_KEY=your_site_key
    KARSER_RECAPTCHA_SECRET_KEY=your_secret_key
    
  3. First Use Case: Validate a Form Submission Inject the validator into a controller and use it in a form handler:

    use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3;
    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    #[Route('/contact', name: 'contact')]
    public function contact(Request $request, ValidatorInterface $validator): Response
    {
        $form = $this->createForm(ContactType::class);
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            $constraint = new Recaptcha3();
            $errors = $validator->validate($form->getData(), $constraint);
    
            if (count($errors) === 0) {
                // Proceed with submission
            }
        }
        return $this->render('contact.html.twig', ['form' => $form->createView()]);
    }
    
  4. Add reCAPTCHA to a Form Use the Recaptcha3 constraint in your form type:

    use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3;
    
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('email')
            ->add('message')
            ->add('recaptcha', Recaptcha3::class, [
                'mapped' => false,
                'threshold' => 0.5, // Optional: Default is 0.5
            ]);
    }
    
  5. Render the reCAPTCHA Widget In your Twig template:

    {{ form_widget(form.recaptcha) }}
    

Implementation Patterns

Common Workflows

1. Dynamic Thresholds

Adjust thresholds based on user behavior or risk levels:

// In a controller or service
$constraint = new Recaptcha3(['threshold' => $dynamicThreshold]);

2. API Endpoints

Validate reCAPTCHA scores in API requests using a custom validator:

use Karser\Recaptcha3Bundle\Validator\Recaptcha3Validator;

public function validateRecaptcha(Request $request, Recaptcha3Validator $validator)
{
    $score = $validator->validateToken($request->request->get('g-recaptcha-response'));
    if ($score < 0.5) {
        throw new \RuntimeException('reCAPTCHA validation failed');
    }
    return $score;
}

3. Event-Based Validation

Use Symfony events to validate reCAPTCHA before form submission:

// src/EventListener/RecaptchaListener.php
use Karser\Recaptcha3Bundle\Validator\Recaptcha3Validator;
use Symfony\Component\HttpKernel\Event\RequestEvent;

class RecaptchaListener
{
    public function __construct(private Recaptcha3Validator $validator) {}

    public function onKernelRequest(RequestEvent $event)
    {
        if ($event->isMainRequest() && $event->getRequest()->isXmlHttpRequest()) {
            $score = $this->validator->validateToken($event->getRequest()->request->get('g-recaptcha-response'));
            if ($score < 0.3) {
                $event->setResponse(new JsonResponse(['error' => 'reCAPTCHA failed'], 403));
            }
        }
    }
}

4. Integration with Symfony Security

Create a custom voter to block high-risk submissions:

use Karser\Recaptcha3Bundle\Validator\Recaptcha3Validator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class RecaptchaVoter extends Voter
{
    public function __construct(private Recaptcha3Validator $validator) {}

    protected function supports(string $attribute, $subject): bool
    {
        return $attribute === 'RECAPTCHA_VALID';
    }

    protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
    {
        $score = $this->validator->validateToken($subject->getRecaptchaToken());
        return $score >= 0.5;
    }
}

5. Batch Processing

Validate reCAPTCHA scores in bulk (e.g., for imported data):

use Karser\Recaptcha3Bundle\Validator\Recaptcha3Validator;

public function processBatch(array $submissions, Recaptcha3Validator $validator)
{
    $validSubmissions = [];
    foreach ($submissions as $submission) {
        $score = $validator->validateToken($submission['recaptcha_token']);
        if ($score >= 0.5) {
            $validSubmissions[] = $submission;
        }
    }
    return $validSubmissions;
}

Integration Tips

Frontend Integration

Include the reCAPTCHA script in your base template (base.html.twig):

<script src="https://www.google.com/recaptcha/api.js?render={{ app.env('KARSER_RECAPTCHA_SITE_KEY') }}"></script>

Add a hidden field to your forms:

<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response">

Use JavaScript to auto-fill the token:

grecaptcha.ready(function() {
    grecaptcha.execute('{{ app.env('KARSER_RECAPTCHA_SITE_KEY') }}', {action: 'submit'})
        .then(function(token) {
            document.getElementById('g-recaptcha-response').value = token;
        });
});

Custom Error Messages

Override default validation messages in your form type:

$builder->add('recaptcha', Recaptcha3::class, [
    'mapped' => false,
    'message' => 'This submission looks like it might be automated. Please try again.',
]);

Testing

Use the Recaptcha3Validator to mock responses in tests:

use Karser\Recaptcha3Bundle\Validator\Recaptcha3Validator;

public function testRecaptchaValidation(Recaptcha3Validator $validator)
{
    $validator->setTestMode(true); // Enable test mode
    $validator->setExpectedScore(0.9); // Simulate a high score

    $this->assertTrue($validator->validateToken('fake_token'));
}

Gotchas and Tips

Pitfalls

  1. Token Expiry

    • reCAPTCHA tokens expire after 2 minutes. Ensure your frontend submits the form immediately after token generation.
    • Fix: Use grecaptcha.execute() in the form submission handler (e.g., with onsubmit).
  2. Threshold Misconfiguration

    • Default threshold (0.5) may be too lenient for high-risk actions (e.g., password resets).
    • Fix: Increase the threshold (e.g., 0.9) for sensitive operations:
      $constraint = new Recaptcha3(['threshold' => 0.9]);
      
  3. Missing mapped => false

    • Forgetting to set mapped => false in the form field will cause validation errors.
    • Fix: Always include it:
      $builder->add('recaptcha', Recaptcha3::class, ['mapped' => false]);
      
  4. Caching Issues

    • Symfony’s validator cache may retain old reCAPTCHA responses if not invalidated.
    • Fix: Clear the cache after changing thresholds or keys:
      php bin/console cache:clear
      
  5. IP-Based Rate Limits

    • Google may block requests if you exceed their rate limits (e.g., >1000 requests/minute).
    • Fix: Implement client-side caching of tokens or use a queue system for bulk submissions.
  6. Test Mode Pitfalls

    • Forgetting to disable test mode in production can expose your secret key.
    • Fix: Ensure .env has:
      KARSER_RECAPTCHA_TEST_MODE=false
      

Debugging Tips

  1. Log Scores for Analysis Extend the validator to log scores for debugging:
    use Psr\Log\LoggerInterface;
    
    class CustomRecaptchaValidator extends Recaptcha3Validator
    {
        public function __construct(LoggerInterface $logger)
        {
            $this->logger = $logger
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor