Cloudflare's Turnstile Service is a captcha-like bot detection and mitigation service that helps protect your website from malicious traffic. This library provides a Spring Boot service that integrates with Cloudflare's Turnstile Service to protect your website from bots. It provides a simple and easy-to-use interface for configuring and using the Turnstile Service in your Spring Boot application.
Read more about Cloudflare's Turnstile Service here.
You will need a Cloudflare Account, and to create a Turnstile Widget for your site, which will give you a Site Key and Secret to use with this library.
- Easy configuration using Spring Boot's
application.yml
orapplication.properties
. - Handles API requests and responses seamlessly.
- Provides a simple interface validating Cloudflare Turnstile tokens.
- Includes monitoring and metrics via Spring Actuator integration.
- Health checks to verify Cloudflare connectivity and service status.
- Detailed validation statistics for operational visibility.
- Java 17 or later
- Gradle 8.10.1 or Maven 3.8.1+
- Cloudflare Turnstile Site Key and Secret
The library is available through the Maven Central Repository. You can include it in your Spring Boot project using either Maven or Gradle.
Add the following dependency to your pom.xml
:
<dependency>
<groupId>com.digitalsanctuary</groupId>
<artifactId>ds-spring-cf-turnstile</artifactId>
<version>1.1.7</version>
</dependency>
Add the following dependency to your build.gradle
:
dependencies {
implementation 'com.digitalsanctuary:ds-spring-cf-turnstile:1.1.7'
}
Configure the library using the application.yml
file located in
src/main/resources
You need to setup your Turnstile Site Key and Secret in the application.yml
file.
ds:
cf:
turnstile:
sitekey: # Turnstile Site Key
secret: # Turnstile Secret
# Optional monitoring configuration
metrics:
enabled: true
health-check-enabled: true
error-threshold: 10
To add Cloudflare Turnstile to your website, include the following script in your HTML:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer></script>
Add the Turnstile widget to your form with the cf-turnstile
class and the data-sitekey
attribute set to your Turnstile Site Key:
<form id="login-form" action="/login" method="post">
<input type="email" name="email" placeholder="Email" required>
<div class="cf-turnstile" data-sitekey="$YOUR_SITE_KEY"></div>
<button type="submit">Login</button>
</form>
If you are using Thymeleaf, you can use the following code:
<form id="login-form" action="#" th:action="@{/login}" method="post">
<input type="email" name="email" placeholder="Email" required>
<div class="cf-turnstile" th:data-sitekey="${@turnstileValidationService.getTurnstileSitekey()}"></div>
<button type="submit">Login</button>
</form>
And the site key will be automatically populated from the application.yml
file.
Use the TurnstileValidationService
to validate Turnstile tokens from your Controller:
The Turnstile token is passed as a request parameter named cf-turnstile-response
. You can access the token by adding a @RequestParam
annotation to your controller method.
@RequestParam(name = "cf-turnstile-response", required = true) String turnstileResponse
Here's a complete example:
import com.digitalsanctuary.cf.turnstile.service.TurnstileValidationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class LoginController {
@Autowired
private TurnstileValidationService turnstileValidationService;
@Autowired
private UserService userService;
@PostMapping("/login")
public String login(Model model,
@RequestParam String email,
@RequestParam(name = "cf-turnstile-response", required = true) String turnstileResponse,
HttpServletRequest request) {
// Get the client IP address (recommended for security)
String clientIpAddress = turnstileValidationService.getClientIpAddress(request);
// Validate the Turnstile response token
boolean turnstileValid = turnstileValidationService.validateTurnstileResponse(turnstileResponse, clientIpAddress);
if (!turnstileValid) {
log.warn("Turnstile validation failed for login request with email: {}", email);
model.addAttribute("error", "Security verification failed. Please try again.");
return "login";
}
// Handle the login process normally
if (userService.authenticateUser(email)) {
return "redirect:/dashboard";
} else {
model.addAttribute("error", "Invalid login credentials");
return "login";
}
}
}
If you don't need to validate the client IP address, you can use the simplified method:
boolean turnstileValid = turnstileValidationService.validateTurnstileResponse(turnstileResponse);
When integrating Cloudflare Turnstile into your application, keep these security considerations in mind:
-
Protect your secret key: Never expose your Turnstile Secret key in client-side code or public repositories.
-
Always validate on the server: Never rely solely on client-side validation. Always validate Turnstile tokens on your server.
-
Use IP validation: When possible, include the client's IP address in the validation request for an additional layer of security.
-
Implement proper error handling: Don't provide detailed error messages to users that could reveal implementation details.
-
Add rate limiting: Consider implementing rate limiting on endpoints that use Turnstile validation to prevent abuse.
-
Monitor validation failures: Track and alert on unusual patterns of validation failures, which could indicate an attack.
SpringCFTurnstile includes comprehensive monitoring and metrics capabilities through Spring Boot Actuator integration.
The following metrics are automatically collected and can be accessed through Spring Boot Actuator:
turnstile.validation.requests
: Total number of validation requeststurnstile.validation.success
: Number of successful validationsturnstile.validation.errors
: Number of failed validationsturnstile.validation.errors.network
: Network-related errorsturnstile.validation.errors.config
: Configuration errorsturnstile.validation.errors.token
: Invalid token errorsturnstile.validation.errors.input
: Input validation errorsturnstile.validation.response.time
: Response time metrics for Turnstile API calls
A custom health indicator is included that reports on the Turnstile service status. It will check:
- Proper service configuration (secret key, URL)
- Error rate compared to configured threshold
- Validation statistics
Metrics and monitoring can be configured in your application.yml
:
ds:
cf:
turnstile:
metrics:
# Enable/disable metrics collection
enabled: true
# Enable/disable health check endpoint
health-check-enabled: true
# Set error threshold percentage for health degradation
error-threshold: 10
The metrics can be integrated with monitoring systems such as Prometheus, Grafana, and others through standard Spring Boot Actuator endpoints.
To enable full monitoring capabilities, include Spring Boot Actuator in your project:
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Spring Cloudflare Turnstile uses Spring Boot's auto-configuration to seamlessly integrate with your application:
-
Auto-configuration: The library is automatically configured when included in your Spring Boot application.
-
Configuration Properties: Properties are loaded from your application configuration files.
-
Service Layer: The
TurnstileValidationService
provides methods for validating tokens and retrieving configuration. -
HTTP Client: Uses Spring's
RestClient
to communicate with Cloudflare's API. -
Metrics Layer: Metrics collection through Micrometer and Spring Boot Actuator.
-
Health Indicators: Health checks to verify Cloudflare connectivity and service status.
-
DTO Layer: Response objects map directly to Cloudflare's API responses.
Contributions are welcome! Please see CONTRIBUTING.md for details on how to contribute to this project.
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
For questions or support, please open an issue on the GitHub repository.