Skip to content

Java Client

The EU CAPTCHA Java client is available in three variants published to Maven Central. All three expose the same imports and request/response model — the difference is the underlying HTTP library and the target Spring version.

Variant Artifact ID HTTP library Java Spring
java-resttemplate eu-captcha-java-resttemplate Spring RestTemplate 17+ Spring Framework 6 (WebMVC, synchronous)
java-webflux-boot2 eu-captcha-java-webflux-boot2 Spring WebClient 8+ Spring Boot 2 / WebFlux (reactive)
java-webflux-boot3 eu-captcha-java-webflux-boot3 Spring WebClient 17+ Spring Boot 3 / Jakarta EE (reactive)

Use java-resttemplate for traditional Spring MVC applications, java-webflux-boot2 for Spring Boot 2 reactive applications, and java-webflux-boot3 for Spring Boot 3 applications that use the Jakarta EE namespace.

Installation

All three variants share the same groupId (com.myrasec) and version (1.0.0). Replace ARTIFACT_ID with the variant you need.

Maven:

<dependency>
  <groupId>com.myrasec</groupId>
  <artifactId>ARTIFACT_ID</artifactId>
  <version>1.0.0</version>
</dependency>

Gradle:

implementation "com.myrasec:ARTIFACT_ID:1.0.0"

For example, to use the RestTemplate variant:

<dependency>
  <groupId>com.myrasec</groupId>
  <artifactId>eu-captcha-java-resttemplate</artifactId>
  <version>1.0.0</version>
</dependency>

Usage — java-resttemplate

Synchronous. Returns VerifyResponse directly. Use this variant with Spring MVC / servlet-based applications.

import com.myrasec.client.ApiClient;
import com.myrasec.client.api.EuCaptchaApi;
import com.myrasec.client.model.VerifyRequest;
import com.myrasec.client.model.VerifyResponse;
import org.springframework.web.client.RestClientException;

ApiClient client = new ApiClient(); // thread-safe; create once and share

EuCaptchaApi api = new EuCaptchaApi(client);

VerifyRequest request = new VerifyRequest()
        .sitekey(System.getenv("EUCAPTCHA_SITE_KEY"))
        .secret(System.getenv("EUCAPTCHA_SECRET_KEY"))
        .clientIp(clientIp)           // real end-user IP — see below
        .clientToken(euCaptchaToken)  // value of the "eu-captcha-response" POST field
        .clientUserAgent(userAgent);  // value of the User-Agent request header

try {
    VerifyResponse response = api.verifyClientToken(request);

    if (response.isTrainingMode()) {
        // Validation was bypassed — sitekey missing, secret wrong, or protection disabled.
        // Check your credentials immediately if you see this in production.
        denyAccess();
    } else if (Boolean.TRUE.equals(response.getSuccess())) {
        allowAccess();
    } else {
        denyAccess();
    }
} catch (RestClientException e) {
    // Network error or unexpected HTTP status.
    // Decide your fallback policy: allow or deny.
    log.error("EU CAPTCHA verification failed: {}", e.getMessage());
}

Usage — java-webflux-boot2 and java-webflux-boot3

Reactive. verifyClientToken returns Mono<VerifyResponse>. Compose it into your handler chain rather than calling .block(). The two variants are identical in API — the only difference is the Spring Boot and Jakarta EE version they target.

import com.myrasec.client.ApiClient;
import com.myrasec.client.api.EuCaptchaApi;
import com.myrasec.client.model.VerifyRequest;
import com.myrasec.client.model.VerifyResponse;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

ApiClient client = new ApiClient(); // thread-safe; create once and share

EuCaptchaApi api = new EuCaptchaApi(client);

VerifyRequest request = new VerifyRequest()
        .sitekey(System.getenv("EUCAPTCHA_SITE_KEY"))
        .secret(System.getenv("EUCAPTCHA_SECRET_KEY"))
        .clientIp(clientIp)
        .clientToken(euCaptchaToken)
        .clientUserAgent(userAgent);

Mono<VerifyResponse> result = api.verifyClientToken(request)
        .map(response -> {
            if (response.isTrainingMode()) {
                denyAccess();
            } else if (Boolean.TRUE.equals(response.getSuccess())) {
                allowAccess();
            } else {
                denyAccess();
            }
            return response;
        })
        .onErrorResume(WebClientResponseException.class, e -> {
            log.error("EU CAPTCHA verification failed: {}", e.getMessage());
            return Mono.empty(); // decide your fallback policy
        });

// In a WebFlux handler, return the Mono directly:
// return result.then(ServerResponse.ok().build());

Extracting the real client IP

Always pass the real end-user IP address, not the IP of your reverse proxy or CDN.

Spring MVC (HttpServletRequest):

String clientIp = request.getRemoteAddr();

// Behind a reverse proxy or CDN:
String forwarded = request.getHeader("X-Forwarded-For");
if (forwarded != null && !forwarded.isBlank()) {
    clientIp = forwarded.split(",")[0].trim();
}

Spring WebFlux (ServerWebExchange):

String clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();

// Behind a reverse proxy or CDN:
String forwarded = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
if (forwarded != null && !forwarded.isBlank()) {
    clientIp = forwarded.split(",")[0].trim();
}

VerifyRequest fields

Field Type Description
sitekey(String) required Your public sitekey
secret(String) required Your secret key — keep server-side only
clientIp(String) required Visitor's IPv4 or IPv6 address. Use X-Forwarded-For or X-Client-IP when behind a proxy or CDN.
clientToken(String) required Value of the eu-captcha-response form field. Pass an empty string if the widget did not complete — always submit it.
clientUserAgent(String) required Visitor's User-Agent header

VerifyResponse fields

Method Type Description
getSuccess() Boolean true if the token passed verification
isTrainingMode() boolean true if validation was skipped and success is forced to true. Check your sitekey and secret immediately if you see this in production. See server-side verification for details.

Security

  • ApiClient is thread-safe. Create one instance and share it across your application — do not create a new instance per request.
  • Store credentials in environment variables or a secrets manager — never in source code.
  • Do not enable ApiClient.setDebugging(true) in production. Debug mode logs the full request body; the raw HTTP payload is not redacted even though VerifyRequest.toString() masks the secret.

Building from source

If you prefer to build locally rather than pulling from Maven Central:

git clone https://github.com/Myra-Security-GmbH/eu-captcha-java.git
cd eu-captcha-java/java-resttemplate   # or java-webflux-boot2 / java-webflux-boot3
mvn clean install

To generate your own client for a different language from the OpenAPI spec, see OpenAPI Generator.