Error trying implement Recaptcha custom flow

Hi, I´m trying integrate recaptcha with keycloak for login, but i’m getting this error when i do the login action

keycloak | 2024-05-10 17:29:16,474 WARN [org.keycloak.services] (executor-thread-17) KC-SERVICES0013: Failed authentication: java.lang.NullPointerException: Cannot invoke “org.keycloak.authentication.FlowStatus.ordinal()” because “status” is null
keycloak | at org.keycloak.authentication.DefaultAuthenticationFlow.processResult(DefaultAuthenticationFlow.java:484)
keycloak | at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:155)
keycloak | at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:988)
keycloak | at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:362)
keycloak | at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:333)
keycloak | at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:325)
keycloak | at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:390)
keycloak | at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$authenticateForm_32b8e198ac3110abd1d5774e83a4cf87858129f4.invoke(Unknown Source)
keycloak | at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
keycloak | at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
keycloak | at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145)
keycloak | at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
keycloak | at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
keycloak | at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
keycloak | at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
keycloak | at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
keycloak | at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
keycloak | at java.base/java.lang.Thread.run(Thread.java:840)

Hier is my login scream, the recaptcha appears, but when i click in log in this error occurs

image

Hier is my Authenticator

public class RecaptchaUsernamePasswordForm extends UsernamePasswordForm implements Authenticator {

  public static final String G_RECAPTCHA_RESPONSE = "g-recaptcha-response";
  public static final String RECAPTCHA_REFERENCE_CATEGORY = "recaptcha";
  public static final String SITE_KEY = "site.key";
  public static final String SITE_SECRET = "secret";
  private static final Logger logger = Logger.getLogger(RecaptchaUsernamePasswordForm.class);
  private String defaultSiteKey;
  private String defaultServerKey;

  @Override
  public void authenticate(AuthenticationFlowContext context) {
	  context.getEvent()
			  .detail(Details.AUTH_METHOD, "auth_method");
	  if (logger.isInfoEnabled()) {
		  logger.info(
				  "validateRecaptcha(AuthenticationFlowContext, boolean, String, String) - Before the validation");
	  }

	  AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
	  LoginFormsProvider form = context.form();
	  String userLanguageTag = context.getSession()
			  .getContext()
			  .resolveLocale(context.getUser())
			  .toLanguageTag();

	  if (StringUtil.isNotBlank(defaultServerKey) && StringUtil.isNotBlank(defaultSiteKey)) {
		  form.setAttribute("recaptchaSiteKey", defaultSiteKey);
	  } else if (captchaConfig == null || captchaConfig.getConfig() == null || captchaConfig.getConfig()
			  .get(SITE_KEY) == null || captchaConfig.getConfig()
			  .get(SITE_SECRET) == null) {
		  form.addError(new FormMessage(null, Messages.RECAPTCHA_NOT_CONFIGURED));
		  return;
	  } else{
		  String siteKey = captchaConfig.getConfig()
				  .get(SITE_KEY);
		  form.setAttribute("recaptchaSiteKey", siteKey);
	  }
	  form.setAttribute("recaptchaRequired", true);
	  form.addScript("https://www.google.com/recaptcha/api.js?hl=" + userLanguageTag);

	  super.authenticate(context);
  } 
}

and my Factory


public class RecaptchaUsernamePasswordFormFactory extends UsernamePasswordFormFactory implements AuthenticatorFactory {

	public static final String PROVIDER_ID = "recaptcha-form";
	public static final RecaptchaUsernamePasswordForm SINGLETON = new RecaptchaUsernamePasswordForm();
	private static final Logger logger = Logger.getLogger(RecaptchaUsernamePasswordFormFactory.class);
	private String siteKey;
	private String serverKey;

	@Override
	public void init(Config.Scope config) {
		this.siteKey = config.get("siteKey");
		this.serverKey = config.get("serverKey");
		SINGLETON.setEnvironment(siteKey, serverKey);
	}

	@Override
	public Authenticator create(KeycloakSession session) {
		return SINGLETON;
	}

	@Override
	public void postInit(KeycloakSessionFactory factory) {

	}

	@Override
	public void close() {

	}

	@Override
	public String getId() {
		return PROVIDER_ID;
	}

	@Override
	public String getReferenceCategory() {
		return UserCredentialModel.PASSWORD;
	}

	@Override
	public boolean isConfigurable() {
		return true;
	}

	public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
			AuthenticationExecutionModel.Requirement.REQUIRED };

	@Override
	public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
		return REQUIREMENT_CHOICES;
	}

	@Override
	public String getDisplayType() {
		return "Recaptcha Username Password Form";
	}

	@Override
	public String getHelpText() {
		return "Validates a username and password from login form + google recaptcha";
	}

	@Override
	public List<ProviderConfigProperty> getConfigProperties() {
		return null;
	}

	@Override
	public boolean isUserSetupAllowed() {
		return false;
	}

}

Hi Lucas, did you solved this?
I have similiar situation for my custom flow…

Not OP, but in my case in code based on raptor-group/keycloak-login-recaptcha, the issue was in the failure path here keycloak-login-recaptcha/src/main/java/org/keycloak/marjaa/providers/login/recaptcha/authenticator/RecaptchaUsernamePasswordForm.java at a75fde67cf64d75b9a3e4cb9b6e162eee1b2a432 · raptor-group/keycloak-login-recaptcha · GitHub.

Adding something like context.failureChallenge(AuthenticationFlowError.INTERNAL_ERROR, challenge(context, somemessage)) appears to fix it. This is based on the failure patterns found in AbstractUsernameFormAuthenticator keycloak/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java at release/25.0 · keycloak/keycloak · GitHub.