Guide

1. Getting Started

The Oorian ReCaptcha library integrates Google reCAPTCHA v3 into Oorian web applications. reCAPTCHA v3 is invisible to users and returns a score indicating the likelihood that the interaction is from a human, making it ideal for protecting forms without disrupting the user experience.

Key Features

  • Invisible verification — no user interaction required
  • Score-based bot detection (0.0 to 1.0)
  • Automatic token refresh to prevent expiration
  • Simple one-line verification on form submission
  • Full response access for detailed analysis
  • Configurable action names for different forms

Library Components

Class Description
ReCaptcha UI component that renders the hidden token input (extends Div)
ReCaptchaConfig Global configuration for site key, secret key, and version
ReCaptchaVerifier Server-side token verification against Google's API
ReCaptchaResponse Immutable response from Google's verification API
ReCaptchaVersion Enum of reCAPTCHA versions (currently V3 only)

2. Project Setup

Add oorian-recaptcha as a dependency to your Oorian web application or LaunchPad project. The JAR must be included in your project's classpath and packaged into the deployed WAR file.

Download: Get the latest oorian-recaptcha JAR from the download section of the ReCaptcha library page, available as a direct download or via Maven Central.

3. Google reCAPTCHA Setup

Before using the library, you need to register your site with Google reCAPTCHA and obtain a site key and secret key.

Steps

  1. Go to the reCAPTCHA Admin Console (google.com/recaptcha/admin)
  2. Click the + button to register a new site
  3. Enter a label (e.g., "My Application")
  4. Select reCAPTCHA v3 as the type
  5. Add your domain(s) (e.g., myapp.com, localhost for development)
  6. Accept the terms and click Submit
  7. Copy the Site Key (public, used in the browser) and Secret Key (private, used server-side)

Important: The secret key must be kept confidential and never exposed to the client. Only use it server-side for verification. The site key is safe to include in your HTML pages.

4. Configuration

Configure reCAPTCHA keys either through ReCaptchaConfig during application startup or through the ReCaptcha component itself.

Application-Level Configuration (Recommended)

Java
@WebListener
public class MyApplication extends Application
{
    @Override
    protected void initialize(ServletContext servletContext)
    {
        registerPackage("com.mycompany.pages");

        // Configure reCAPTCHA keys
        ReCaptchaConfig.setSiteKey("6LdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
        ReCaptchaConfig.setSecretKey("6LdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
    }
}

Component-Level Configuration

Java
// These delegate to ReCaptchaConfig internally
ReCaptcha captcha = new ReCaptcha();
captcha.setSiteKey("6LdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
captcha.setSecretKey("6LdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

Configuration Options

Method Description
ReCaptchaConfig.setSiteKey(String) Public key used in the browser to generate tokens
ReCaptchaConfig.setSecretKey(String) Private key used server-side for verification
ReCaptchaConfig.setVersion(ReCaptchaVersion) reCAPTCHA version (defaults to V3, currently the only supported version)

5. Basic Usage

The basic integration involves three steps: adding the reCAPTCHA script to the page head, adding the component inside a form, and verifying the token on form submission.

Java
@Page("/contact")
public class ContactPage extends HtmlPage implements FormListener
{
    private ReCaptcha captcha;

    @Override
    protected boolean initializePage()
    {
        captcha = new ReCaptcha();
        return true;
    }

    @Override
    protected void createHead(Head head)
    {
        head.setTitle("Contact Us");

        // Step 1: Add the Google reCAPTCHA script
        captcha.addScript(head);
    }

    @Override
    protected void createBody(Body body)
    {
        OorianForm form = new OorianForm();

        form.addElement(new TextInput("name"));
        form.addElement(new TextInput("email"));

        // Step 2: Add the reCAPTCHA component inside the form
        form.addElement(captcha);

        Button submitBtn = new Button("Send");
        submitBtn.registerListener(this, FormEvent.class);
        form.addElement(submitBtn);

        body.addElement(form);
    }

    @Override
    public void onEvent(FormEvent event)
    {
        Parameters params = event.getParameters();

        // Step 3: Verify the reCAPTCHA token
        String token = params.getParameterValue(ReCaptcha.INPUT_NAME);

        try
        {
            boolean isHuman = captcha.verify(token, 0.5);

            if (isHuman)
            {
                // Process the form
                String name = params.getParameterValue("name");
                String email = params.getParameterValue("email");
                // ... handle submission
            }
            else
            {
                // Suspected bot - show error or ignore
            }
        }
        catch (HttpRequestException e)
        {
            // Error communicating with Google API
        }
    }
}

How it works: The ReCaptcha component renders a hidden <input> named g-recaptcha-response. Client-side JavaScript automatically obtains a reCAPTCHA token from Google and populates the input. The token is refreshed periodically (default: 90 seconds) to prevent expiration. On form submission, the token is sent with the other form parameters and verified server-side.

6. The Verification Flow

Understanding the verification flow helps you integrate reCAPTCHA correctly.

Detailed Flow

  1. Page loads — Google reCAPTCHA script initializes and generates an initial token
  2. Token refresh — Client-side JavaScript periodically refreshes the token (default: every 90 seconds)
  3. Form submission — The current token is sent as the g-recaptcha-response parameter
  4. Server verificationReCaptchaVerifier sends the token and secret key to Google's API
  5. Score evaluation — Google returns a score (0.0 to 1.0) and the server checks against the threshold

Token Refresh

reCAPTCHA tokens expire after approximately 2 minutes. The component automatically refreshes the token at a configurable interval to ensure it is always valid when the form is submitted.

Java
ReCaptcha captcha = new ReCaptcha();

// Default: 90000 ms (90 seconds)
captcha.setRefreshInterval(60000); // Refresh every 60 seconds

7. The Verification Response

For detailed analysis beyond a simple pass/fail, use getVerificationResponse() (on the component) or ReCaptchaVerifier.getResponse() to get the full response from Google's API.

Java
String token = params.getParameterValue(ReCaptcha.INPUT_NAME);
ReCaptchaResponse response = ReCaptchaVerifier.getResponse(token);

if (response.isSuccess())
{
    double score = response.getScore();
    String action = response.getAction();
    String timestamp = response.getChallengeTimestamp();
    String hostname = response.getHostname();

    if (score >= 0.5 && "login".equals(action))
    {
        // Verified: high confidence human on the login form
    }
}

ReCaptchaResponse Fields

Method Returns Description
isSuccess() boolean Whether the token was valid
getScore() double Confidence score (0.0 = bot, 1.0 = human)
getAction() String The action name passed when generating the token
getChallengeTimestamp() String ISO 8601 timestamp of the challenge
getHostname() String Hostname where the token was generated

8. Score Thresholds

reCAPTCHA v3 returns a score from 0.0 to 1.0, where 1.0 is the highest confidence that the interaction is from a human. You choose the threshold that's right for your use case.

Score Range Interpretation Recommended Action
0.9 - 1.0 Very likely human Process normally
0.7 - 0.9 Probably human Process normally
0.5 - 0.7 Uncertain Consider additional verification
0.3 - 0.5 Suspicious Add friction (e.g., email verification)
0.0 - 0.3 Very likely bot Block or require manual review

Google's recommendation: Start with a threshold of 0.5 and adjust based on your traffic patterns. Monitor your scores over time using the reCAPTCHA Admin Console to understand the score distribution for your site.

Threshold Examples by Use Case

Java
// Contact form - moderate protection
boolean ok = captcha.verify(token, 0.5);

// Login form - stricter protection
boolean ok = captcha.verify(token, 0.7);

// Newsletter signup - lenient (avoid blocking real users)
boolean ok = captcha.verify(token, 0.3);

9. Actions

Actions are labels that identify which form or page generated the reCAPTCHA token. They are included in the verification response and help you detect misuse (e.g., a token generated on the login page being used on the registration page).

Java
// Default action is "submit"
ReCaptcha captcha = new ReCaptcha();

// Custom action for a login form
ReCaptcha loginCaptcha = new ReCaptcha("login");

// Or set the action after construction
captcha.setAction("register");

Verifying the Action

Java
ReCaptchaResponse response = ReCaptchaVerifier.getResponse(token);

if (response.isSuccess()
    && response.getScore() >= 0.5
    && "login".equals(response.getAction()))
{
    // Token is valid, score is acceptable, and action matches
}

Best practice: Always verify the action matches the expected value. This prevents token replay attacks where a token generated on one form is submitted to a different form.

10. Real-World Examples

Login Form with reCAPTCHA

Java
@Page("/login")
public class LoginPage extends HtmlPage implements FormListener
{
    private ReCaptcha captcha;
    private Paragraph errorMsg;

    @Override
    protected boolean initializePage()
    {
        captcha = new ReCaptcha("login");
        errorMsg = new Paragraph();
        return true;
    }

    @Override
    protected void createHead(Head head)
    {
        head.setTitle("Login");
        captcha.addScript(head);
    }

    @Override
    protected void createBody(Body body)
    {
        OorianForm form = new OorianForm();
        form.addElement(new TextInput("username"));
        form.addElement(new PasswordInput("password"));
        form.addElement(captcha);
        form.addElement(errorMsg);

        Button loginBtn = new Button("Log In");
        loginBtn.registerListener(this, FormEvent.class);
        form.addElement(loginBtn);

        body.addElement(form);
    }

    @Override
    public void onEvent(FormEvent event)
    {
        Parameters params = event.getParameters();
        String token = params.getParameterValue(ReCaptcha.INPUT_NAME);

        try
        {
            ReCaptchaResponse response = captcha.getVerificationResponse(token);

            if (!response.isSuccess() || response.getScore() < 0.7)
            {
                errorMsg.setText("Verification failed. Please try again.");
                sendUpdate();
                return;
            }

            // Proceed with authentication
            String username = params.getParameterValue("username");
            String password = params.getParameterValue("password");
            // ... authenticate user
        }
        catch (HttpRequestException e)
        {
            errorMsg.setText("An error occurred. Please try again later.");
            sendUpdate();
        }
    }
}

Using the Static Verifier Directly

If you prefer not to use the component's convenience methods, you can call the ReCaptchaVerifier directly:

Java
String token = params.getParameterValue("g-recaptcha-response");

// Simple pass/fail
boolean isHuman = ReCaptchaVerifier.verify(token, 0.5);

// Full response
ReCaptchaResponse response = ReCaptchaVerifier.getResponse(token);

Adaptive Security

Use different thresholds and actions based on the sensitivity of the operation:

Java
ReCaptchaResponse response = ReCaptchaVerifier.getResponse(token);

if (response.isSuccess())
{
    double score = response.getScore();

    if (score >= 0.7)
    {
        // High confidence - process immediately
        processForm(params);
    }
    else if (score >= 0.4)
    {
        // Medium confidence - require email verification
        sendVerificationEmail(params.getParameterValue("email"));
    }
    else
    {
        // Low confidence - block
        errorMsg.setText("Submission blocked for security reasons.");
        sendUpdate();
    }
}

11. API Reference

ReCaptcha

UI component that renders a hidden token input. Extends Div.

Method Returns Description
ReCaptcha() - Create with default action ("submit") and 90s refresh
ReCaptcha(String action) - Create with a custom action name
setAction(String) void Set the action name (e.g., "login", "register")
setRefreshInterval(int) void Set token refresh interval in milliseconds (default: 90000)
setSiteKey(String) void Set site key (delegates to ReCaptchaConfig)
setSecretKey(String) void Set secret key (delegates to ReCaptchaConfig)
addScript(Head) void Add Google reCAPTCHA script to page head
verify(String, double) boolean Verify token against score threshold
getVerificationResponse(String) ReCaptchaResponse Get full verification response from Google

Constant: ReCaptcha.INPUT_NAME = "g-recaptcha-response"

ReCaptchaConfig

Static configuration class for reCAPTCHA keys and version.

Method Returns Description
setSiteKey(String) void Set the public site key
setSecretKey(String) void Set the private secret key
setVersion(ReCaptchaVersion) void Set the reCAPTCHA version
getSiteKey() String Get the configured site key
getSecretKey() String Get the configured secret key
getVersion() ReCaptchaVersion Get the configured version
addScript(Head) void Add the Google reCAPTCHA script to page head

ReCaptchaVerifier

Static verification class for validating tokens with Google's API.

Method Returns Description
verify(String token, double threshold) boolean Verify token and check score against threshold
getResponse(String token) ReCaptchaResponse Get the full verification response

ReCaptchaResponse

Immutable response from Google's verification API.

Method Returns Description
isSuccess() boolean Whether the token was valid
getScore() double Score from 0.0 (bot) to 1.0 (human)
getAction() String Action name from the token
getChallengeTimestamp() String ISO 8601 challenge timestamp
getHostname() String Hostname where token was generated

ReCaptchaVersion

Enum of reCAPTCHA versions.

Value ID Label Description
V3 3 "v3" reCAPTCHA v3 (invisible, score-based)

12. Troubleshooting

Common Issues

Problem Cause Solution
Token is always null reCAPTCHA script not loaded Ensure captcha.addScript(head) is called in createHead()
HttpRequestException on verify Server cannot reach Google API Check network/firewall settings; ensure www.google.com is accessible
isSuccess() returns false Invalid or expired token Check that the secret key is correct; ensure token hasn't expired
Score is always 0.0 Score not present in response Verify you're using reCAPTCHA v3 (not v2) keys
Token expires before submission User takes too long on the form Reduce refresh interval: captcha.setRefreshInterval(60000)
Low scores for real users New site with little traffic history Lower your threshold temporarily; scores improve as Google learns your traffic

Development Tips

  • Add localhost to your reCAPTCHA domain list for local development
  • Use Google's test keys for automated testing (always returns score 1.0)
  • Monitor your score distribution in the reCAPTCHA Admin Console
  • Log scores in development to understand your baseline before setting thresholds

Testing tip: During development, use ReCaptchaVerifier.getResponse(token) and log the full response to understand what scores your test traffic generates before choosing a production threshold.