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
- Go to the reCAPTCHA Admin Console (google.com/recaptcha/admin)
- Click the + button to register a new site
- Enter a label (e.g., "My Application")
- Select reCAPTCHA v3 as the type
- Add your domain(s) (e.g.,
myapp.com,localhostfor development) - Accept the terms and click Submit
- 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)
@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
// 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.
@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
- Page loads — Google reCAPTCHA script initializes and generates an initial token
- Token refresh — Client-side JavaScript periodically refreshes the token (default: every 90 seconds)
- Form submission — The current token is sent as the
g-recaptcha-responseparameter - Server verification —
ReCaptchaVerifiersends the token and secret key to Google's API - 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.
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.
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
// 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).
// 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
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
@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:
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:
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
localhostto 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.