Using a CAPTCHA Client Extension
Liferay DXP 2025.Q3+
Currently, this feature is behind a release feature flag (LPD-36464).
CAPTCHA challenges are used on websites to verify a human user is accessing it, and not a bot or malicious code attacking the site. Liferay supports two CAPTCHA engine configurations out-of-the-box: SimpleCaptcha and Google’s reCAPTCHA.
If you want to integrate a different third-party CAPTCHA provider, you must use a CAPTCHA client extension. This example re-implements Google’s reCAPTCHA, to help you learn what details are important to change for alternative providers.
The example CAPTCHA client extension used here includes site and secret key values that are not secure and always return success responses. Do not deploy the client extension in a production instance without replacing these keys with your own.
Prerequisites
To start using this client extension,
-
Install a supported version of Java.
NoteCheck the compatibility matrix for supported JDKs, databases, and environments. See JVM Configuration for recommended JVM settings.
-
Clone the
liferay-portal
repository:git clone https://github.com/liferay/liferay-portal.git
Alternatively, you can download the repository in a
.zip
file by navigating to the repository on GitHub and clicking Code → Download ZIP.
Inside the liferay-portal
code repository, the workspaces/liferay-recaptcha-workspace/
folder is a self-contained workspace with the required client extensions.
The liferay-portal
repository also includes an hCaptcha implementation in the workspaces/liferay-hcaptcha-workspace/
folder. You can compare the client extensions in this workspace to the ones in workspaces/liferay-recaptcha-workspace/
for more insight on what configurations to adjust.
Examine the Client Extension
The project you downloaded includes two client extensions: the CAPTCHA client extension and a custom element client extension required for the UI.
When you implement a CAPTCHA client extension, follow your chosen CAPTCHA provider’s instructions to change various parts of the implementation. This process should include generating a site key (for authorizing the UI component on your website with the CAPTCHA provider) and a secret key (for authorizing your code backend with the provider).
Here are the most important parts of the CAPTCHA client extension (and the paired custom element) that you can adjust.
Client Extension YAML Configurations
The CAPTCHA client extension is in the client-extensions/liferay-recaptcha-etc-spring-boot/
folder. It’s defined in the client-extension.yaml
file:
liferay-recaptcha-etc-spring-boot:
captchaName: reCAPTCHA CX
captchaResponseParameterName: g-recaptcha-response
customElementExternalReferenceCode: LXC:liferay-recaptcha-custom-element
name: Liferay reCAPTCHA Etc Spring Boot
oAuth2ApplicationExternalReferenceCode: liferay-recaptcha-etc-spring-boot-oauth-application-user-agent
resourcePath: /validation
type: captcha
This block includes the client extension’s ID (liferay-recaptcha-etc-spring-boot
) and the name that appears in Liferay’s UI (reCAPTCHA CX
). It also references two other client extensions that are required for it to work properly: the custom element client extension (LXC:liferay-recaptcha-custom-element
) and an OAuth 2 user agent client extension.
The captchaResponseParameterName
is necessary to validate user responses. Google’s reCAPTCHA uses the g-recaptcha-response
POST parameter. Set this value to the appropriate response parameter name, according to your chosen CAPTCHA provider.
A malicious client extension could use an unrelated parameter name to extract unsecured details from Liferay’s server responses. Carefully check the configuration to make sure only the CAPTCHA response parameter is used.
The resourcePath
specifies where the CAPTCHA response is sent when the user completes the challenge. In this example client extension, a Spring Boot application receives responses at the /validation
path to verify with Google’s API.
Below these configurations, another block defines an OAuth user agent client extension that’s bundled with the CAPTCHA client extension project. This client extension is necessary for the backend server to communicate with Liferay securely.
liferay-recaptcha-etc-spring-boot-oauth-application-user-agent:
.serviceAddress: localhost:58081
.serviceScheme: http
name: Liferay reCAPTCHA Etc Spring Boot OAuth Application User Agent
type: oAuthApplicationUserAgent
Server Properties
The src/main/resources/application-default.properties
file also contains some important configurations:
liferay.recaptcha.secret=[secret value]
#
# OAuth
#
liferay.oauth.application.external.reference.codes=liferay-recaptcha-etc-spring-boot-oauth-application-user-agent
#
# Spring Boot
#
server.port=58081
The secret key value included in this project is available publicly for instructive purposes. Keep the values secured when you replace this secret key value (and the site key value for the custom element).
The liferay.recaptcha.secret
property authorizes the Spring Boot server to communicate with the CAPTCHA provider to validate user responses. Replace the secret value with a new secret key from your chosen provider.
The liferay.oauth.application.external.reference.codes
value references the OAuth user agent client extension configured in the client-extension.yaml
file.
Spring Boot Server Implementation
After the user completes the challenge, the CAPTCHA client extension must run code to receive the user response and verify it with the third-party provider. You can implement the backend using any server framework as long as it uses an accessible endpoint. In this example, the backend code is implemented as a Spring Boot application.
The most critical file in the Spring Boot implementation is src/main/java/com/liferay/recaptcha/ValidationRestController.java
. In this file, notice that the rest controller handles requests at the /validation
endpoint (the same one configured with the resourcePath
YAML property):
@RequestMapping("/validation")
@RestController
public class ValidationRestController extends BaseRestController {
The post
method contains the key implementation details. First, it generates a JSON object to package the user’s response (and your secret key) before it sends it to the CAPTCHA provider:
JSONObject responseJSONObject = new JSONObject();
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
JSONObject jsonObject = new JSONObject(json);
body.add("remoteip", jsonObject.getString("remoteip"));
body.add("response", jsonObject.getString("response"));
body.add("secret", _secret);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
Then it sends the response to the CAPTCHA provider (in this example, Google’s reCAPTCHA) using a hard-coded verification URL and validates success based on the ResponseEntity
it gets back:
ResponseEntity<String> responseEntity = _restTemplate.postForEntity(
"https://www.google.com/recaptcha/api/siteverify",
new HttpEntity<>(body, httpHeaders), String.class);
When the response is sent back again, Liferay only requires a success
parameter set to true
or false
.
Check your CAPTCHA provider’s instructions to determine which details (such as the specific response parameters or the verification URL) you must change.
Custom Element
The CAPTCHA client extension server handles the backend verification of CAPTCHA responses, but it still needs a frontend interface for users to complete the CAPTCHA challenge. A separate, custom element client extension handles the user interaction in Liferay, which integrates with the CAPTCHA provider’s UI component.
In this example, the custom element is implemented in the client-extensions/liferay-recaptcha-custom-element/
folder, and it uses a component provided by Google’s reCAPTCHA. The component here is included using React, but you can use any frontend framework to integrate with your chosen provider.
In this project folder, the src/components/Captcha.js
file contains this implementation using Google’s provided component:
import React from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
const Captcha = () => {
return (
<div>
<ReCAPTCHA sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI" />
</div>
);
};
export default Captcha;
Within the ReCAPTCHA
element, the sitekey
value allows the component on your website to receive CAPTCHA challenges from your provider. Replace this component with one from your chosen provider, and replace the test API key in this example with the new one you generated.
See Using the Custom Element Type for more information on custom element client extensions.
Start the Microservice
From the client-extensions/liferay-recaptcha-etc-spring-boot/
folder, run
../../gradlew bootRun
The Spring Boot application starts and prints messages in the log:
2025-08-26T08:42:31.470-07:00 INFO 31799 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 58081 (http) with context path '/'
2025-08-26T08:42:31.475-07:00 INFO 31799 --- [ main] c.l.r.RecaptchaSpringBootApplication : Started RecaptchaSpringBootApplication in 1.635 seconds (process running for 1.87)
<==========---> 80% EXECUTING [2m 33s]
Deploy the Client Extensions to Liferay
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.132-ga132
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Once Liferay starts, run this command from the client-extensions/
folder to deploy both client extensions:
../../gradlew clean deploy -Ddeploy.docker.container.id=$(docker ps -lq)
This builds both client extensions and deploys the zip files to Liferay’s deploy/
folder.
To deploy your client extension to Liferay SaaS, use the Liferay Cloud Command-Line Tool to run lcp deploy
.
Confirm the deployment of both client extensions in your Liferay instance’s console:
STARTED liferayrecaptchacustomelement_7.4.3.137
STARTED liferayrecaptchaetcspringboot_7.4.3.137
Now that your client extensions are deployed, configure Liferay to use your CAPTCHA service.
Configure Liferay to Use the Client Extension
-
Log into your Liferay instance.
-
Navigate to the Control Panel → Instance Settings.
-
Under Security, click Security Tools.
-
Make sure CAPTCHA is selected in the side bar, and select reCAPTCHA CX in the CAPTCHA Engine drop-down menu.
ImportantConfiguring your CAPTCHA engine here replaces the CAPTCHA used throughout the entire instance (e.g., any Create Account or Forgot Password pages).
-
Log out from your account.
-
Start to log in again, and click Forgot Password.
The new CAPTCHA appears beneath the input field on the Forgot Password page. If you didn’t replace the site key, the CAPTCHA input also shows a red warning message.
Next Steps
You’ve successfully used a CAPTCHA client extension in Liferay. Next, try exploring other CAPTCHA engines (such as the liferay-hcaptcha-workspace
example) and replacing this example’s implementation details.
You can also try deploying other client extension types: