+----
+
+Any piece of text enclosed in `${}` corresponds to an attribute or template funtion.
+If you see the form's action, you see it points to `${url.loginAction}`.
+This value is automatically generated when you invoke the AuthenticationFlowContext.form() method.
+You can also obtain this value by calling the AuthenticationFlowContext.getActionURL() method in Java code.
+
+You'll also see `${properties.someValue}`.
+These correspond to properties defined in your theme.properties file of our theme.
+ `${msg("someValue")}` corresponds to the internationalized message bundles (.properties files) included with the login theme messages/ directory.
+If you're just using english, you can just add the value of the `loginSecretQuestion` value.
+This should be the question you want to ask the user.
+
+When you call AuthenticationFlowContext.form() this gives you a LoginFormsProvider instance.
+If you called, `LoginFormsProvider.setAttribute("foo", "bar")`, the value of "foo" would be available for reference in your form as `${foo}`.
+The value of an attribute can be any Java bean as well.
+
+[[_adding_authenticator]]
+=== Adding Authenticator to a Flow
+
+Adding an Authenticator to a flow must be done in the admin console.
+If you go to the Authentication menu item and go to the Flow tab, you will be able to view the currently defined flows.
+You cannot modify an built in flows, so, to add the Authenticator we've created you have to copy an existing flow or create your own.
+I'm hoping the UI is intuitive enough so that you can figure out for yourself how to create a flow and add the Authenticator.
+
+After you've created your flow, you have to bind it to the login action you want to bind it to.
+If you go to the Authentication menu and go to the Bindings tab you will see options to bind a flow to the browser, registration, or direct grant flow.
+
+== Required Action Walkthrough
+
+In this section we will discuss how to define a required action.
+In the Authenticator section you may have wondered, "How will we get the user's answer to the secret question entered into the system?". As we showed in the example, if the answer is not set up, a required action will be triggered.
+This section discusses how to implement the required action for the Secret Question Authenticator.
+
+=== Packaging Classes and Deployment
+
+You will package your classes within a single jar.
+This jar does not have to be separate from other provider classes but it must contain a file named `org.keycloak.authentication.RequiredActionFactory` and must be contained in the `META-INF/services/` directory of your jar.
+This file must list the fully qualified classname of each RequiredActionFactory implementation you have in the jar.
+For example:
+
+[source,java]
+----
+org.keycloak.examples.authenticator.SecretQuestionRequiredActionFactory
+----
+
+This services/ file is used by Keycloak to scan the providers it has to load into the system.
+
+To deploy this jar, just copy it to the standalone/configuration/providers directory.
+
+=== Implement the RequiredActionProvider
+
+Required actions must first implement the RequiredActionProvider interface.
+The RequiredActionProvider.requiredActionChallenge() is the initial call by the flow manager into the required action.
+This method is responsible for rendering the HTML form that will drive the required action.
+
+[source,java]
+----
+
+ @Override
+ public void requiredActionChallenge(RequiredActionContext context) {
+ Response challenge = context.form().createForm("secret_question_config.ftl");
+ context.challenge(challenge);
+
+ }
+----
+
+You see that RequiredActionContext has similar methods to AuthenticationFlowContext.
+The form() method allows you to render the page from a Freemarker template.
+The action URL is preset by the call to this form() method.
+You just need to reference it within your HTML form.
+I'll show you this later.
+
+The challenge() method notifies the flow manager that a required action must be executed.
+
+The next method is responsible for processing input from the HTML form of the required action.
+The action URL of the form will be routed to the RequiredActionProvider.processAction() method
+
+[source,java]
+----
+
+ @Override
+ public void processAction(RequiredActionContext context) {
+ String answer = (context.getHttpRequest().getDecodedFormParameters().getFirst("answer"));
+ UserCredentialValueModel model = new UserCredentialValueModel();
+ model.setValue(answer);
+ model.setType(SecretQuestionAuthenticator.CREDENTIAL_TYPE);
+ context.getUser().updateCredentialDirectly(model);
+ context.success();
+ }
+----
+
+The answer is pulled out of the form post.
+A UserCredentialValueModel is created and the type and value of the credential are set.
+Then UserModel.updateCredentialDirectly() is invoked.
+Finally, RequiredActionContext.success() notifies the container that the required action was successful.
+
+=== Implement the RequiredActionFactory
+
+This class is really simple.
+It is just responsible for creating the required actin provider instance.
+
+[source,java]
+----
+
+public class SecretQuestionRequiredActionFactory implements RequiredActionFactory {
+
+ private static final SecretQuestionRequiredAction SINGLETON = new SecretQuestionRequiredAction();
+
+ @Override
+ public RequiredActionProvider create(KeycloakSession session) {
+ return SINGLETON;
+ }
+
+
+ @Override
+ public String getId() {
+ return SecretQuestionRequiredAction.PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayText() {
+ return "Secret Question";
+ }
+----
+
+The getDisplayText() method is just for the admin console when it wants to display a friendly name for the required action.
+
+=== Enable Required Action
+
+The final thing you have to do is go into the admin console.
+Click on the Authentication left menu.
+Click on the Required Actions tab.
+Click on the Register button and choose your new Required Action.
+Your new required action should now be displayed and enabled in the required actions list.
+
+== Modifying/Extending the Registration Form
+
+It is entirely possible for you to implement your own flow with a set of Authenticators to totally change how regisration is done in Keycloak.
+But what you'll usually want to do is just add a little bit of validation to the out of the box registration page.
+An additional SPI was created to be able to do this.
+It basically allows you to add validation of form elements on the page as well as to initialize UserModel attributes and data after the user has been registered.
+We'll look at both the implementation of the user profile registration processing as well as the registration Google Recaptcha plugin.
+
+=== Implementation FormAction Interface
+
+The core interface you have to implement is the FormAction interface.
+A FormAction is responsible for rendering and processing a portion of the page.
+Rendering is done in the buildPage() method, validation is done in the validate() method, post validation operations are done in success(). Let's first take a look at buildPage() method of the Recaptcha plugin.
+
+[source,java]
+----
+
+ @Override
+ public void buildPage(FormContext context, LoginFormsProvider form) {
+ AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
+ 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;
+ }
+ String siteKey = captchaConfig.getConfig().get(SITE_KEY);
+ form.setAttribute("recaptchaRequired", true);
+ form.setAttribute("recaptchaSiteKey", siteKey);
+ form.addScript("https://www.google.com/recaptcha/api.js");
+ }
+----
+
+The Recaptcha buildPage() method is a callback by the form flow to help render the page.
+It receives a form parameter which is a LoginFormsProvider.
+You can add additional attributes to the form provider so that they can be displayed in the HTML page generated by the registration Freemarker template.
+
+The code above is from the registration recaptcha plugin.
+Recaptcha requires some specific settings that must be obtained from configuration.
+FormActions are configured in the exact same was as Authenticators are.
+In this example, we pull the Google Recaptcha site key from configuration and add it as an attribute to the form provider.
+Our regstration template file can read this attribute now.
+
+Recaptcha also has the requirement of loading a javascript script.
+You can do this by calling LoginFormsProvider.addScript() passing in the URL.
+
+For user profile processing, there is no additional information that it needs to add to the form, so its buildPage() method is empty.
+
+The next meaty part of this interface is the validate() method.
+This is called immediately upon receiving a form post.
+Let's look at the Recaptcha's plugin first.
+
+[source,java]
+----
+
+ @Override
+ public void validate(ValidationContext context) {
+ MultivaluedMap