Skip to content
Myra EU CAPTCHA Online Help Updated · 25 Aug 2026

Java

For Java, there are three clients. All three are made from the same OpenAPI description and call the same endpoint. They differ in the Spring technology that they use.

Select the client

Application Client
Spring Boot 3 with Jakarta EE java-webflux-boot3
Spring Boot 2 or Spring 5, reactive java-webflux-boot2
Spring MVC on the servlet stack, Spring 6 java-resttemplate
Client Requirements Interface
java-resttemplate Java 17, Spring Framework 6 Synchronous: VerifyResponse verifyClientToken(VerifyRequest). Repeats requests for the 5xx and 429 status codes with an increasing interval.
java-webflux-boot2 Java 8, Spring Boot 2 with Spring WebFlux Reactive: Mono<VerifyResponse> verifyClientToken(VerifyRequest)
java-webflux-boot3 Java 17, Spring Boot 3 with Jakarta EE 10 Reactive: Mono<VerifyResponse> verifyClientToken(VerifyRequest). Uses annotations from jakarta.* throughout.

Embed the client

Embed the selected client with Maven. The example shows java-resttemplate:

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

With Gradle, the entry is as follows:

implementation "com.myrasec:eu-captcha-java-resttemplate:1.0.0"

You make the client from the sources with this command:

mvn clean install

Verify the token

This example shows the synchronous verification with java-resttemplate:

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();
// client.setMaxAttemptsForRetry(3); // optional: retry up to 3 times on 5xx / 429

EuCaptchaApi api = new EuCaptchaApi(client);

VerifyRequest request = new VerifyRequest()
        .sitekey("YOUR_SITEKEY")
        .secret("YOUR_SECRET")
        .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()) {
        // Training mode: real validation was not performed — always allow.
        // Occurs when the sitekey does not exist, the secret is wrong,
        // or the sitekey is configured with train=true.
        allowAccess();
    } 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());
}

Reactive verification

The two clients for WebFlux give a Mono<VerifyResponse>. Put it in your processing chain instead of a .block() call:

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; share a single instance

EuCaptchaApi api = new EuCaptchaApi(client);

VerifyRequest request = new VerifyRequest()
        .sitekey("YOUR_SITEKEY")
        .secret("YOUR_SECRET")
        .clientIp(clientIp)
        .clientToken(euCaptchaToken)
        .clientUserAgent(userAgent);

Mono<VerifyResponse> result = api.verifyClientToken(request)
        .map(response -> {
            if (response.isTrainingMode()) {
                allowAccess();
            } 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();
        });

Get the IP address of the visitor

Always give the true IP address of the visitor, not the address of your upstream system.

In an application on the servlet stack:

// Without a proxy
String clientIp = httpServletRequest.getRemoteAddr();

// Behind a reverse proxy or CDN (use the header your provider documents)
String forwarded = httpServletRequest.getHeader("X-Forwarded-For");
if (forwarded != null && !forwarded.isBlank()) {
    // X-Forwarded-For is a comma-separated list; the leftmost entry is the client IP
    clientIp = forwarded.split(",")[0].trim();
}

In an application with WebFlux:

// In a Spring WebFlux handler (ServerWebExchange)
String clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();

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

The X-Forwarded-For header contains a list with commas between the entries. The first entry is the IP address of the visitor.

Fields of the request

Field Type Necessary Content
sitekey String yes Public sitekey from the Details view.
secret String yes Secret key for the sitekey.
clientIp String yes IPv4 or IPv6 address of the visitor.
clientToken String yes Token from verify.js. The value can be empty.
clientUserAgent String yes Value of the User-Agent header from the request of the visitor.

Fields of the response

Field Type Content
success Boolean true when the challenge passed.
train Boolean true when the training mode was on. The isTrainingMode() method reads this field.

The endpoint is POST /verify at https://api.eu-captcha.eu/v1. An authorization is not necessary. The request identifies itself with the secret field.

Security

Warning

Do not set ApiClient.setDebugging(true) in production. In debug mode, the client writes the full JSON body to the log. VerifyRequest.toString() hides the secret. The transmitted body does not hide it.

Put the secret in an environment variable or in a key management system, never in the source code.

ApiClient is thread-safe. Make one instance and use it in the full application instead of a new instance for each request.

Full example

See Angular and Java.