Hi all,
Sorry for the longer message, a short TL;DR: Why is my privacy_policy information not available in the first registration event?
Longer version: During registration we can ask customers to accept the terms and conditions using the following required action and updating the registration flow: Server Administration Guide
Now I need to add a second checkbox here, in particular I need users to also agree to our data privacy policy. This needs to be a separate checkbox, so I cannot use the terms and conditions to ask for both. My plan was now as follows.
A. Create a PrivacyPolicy RequiredAction. This is a near carbon copy of the TermsAndConditions required action: keycloak/services/src/main/java/org/keycloak/authentication/requiredactions/TermsAndConditions.java at main · keycloak/keycloak · GitHub
@AutoService(org.keycloak.authentication.RequiredActionFactory.class) public class PrivacyPolicy implements RequiredActionProvider, RequiredActionFactory
B. The PrivacyPolicy Required Action cannot be added to the registration flow, so I created a separate RegistrationPrivacyPolicy. Again, this is a near carbon copy of the RegistrationTermsAndConditions: keycloak/services/src/main/java/org/keycloak/authentication/forms/RegistrationTermsAndConditions.java at 6b300833e25f2c9d25103cb46650f6dd6e8a39c8 · keycloak/keycloak · GitHub
C. After creating both I need to persist the information about accepting the user privacy policy. For this I extended the RegistrationUserCreation class.
@AutoService(org.keycloak.authentication.FormActionFactory.class) public class ExtenedRegistrationUserCreation extends RegistrationUserCreation
In particular, I have overriden the success method to also store my privacy policy information.
@Override
public void success(FormContext context) {
super.success(context);
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
UserModel user = context.getUser();
if (“on”.equals(formData.getFirst(RegistrationPrivacyPolicy.FIELD))) {
// if accepted terms and conditions checkbox, remove action and add the attribute if enabled
RequiredActionProviderModel tacModel = context.getRealm().getRequiredActionProviderByAlias(PrivacyPolicy.PROVIDER_ID);
if (tacModel != null && tacModel.isEnabled()) {
user.setSingleAttribute(PrivacyPolicy.USER_ATTRIBUTE, Integer.toString(Time.currentTime()));
context.getAuthenticationSession().removeRequiredAction(PrivacyPolicy.PROVIDER_ID);
user.removeRequiredAction(PrivacyPolicy.PROVIDER_ID);
}
}
}
D. Bringing it all together. I copied the existing registration flow. Added Terms and Conditions and Privacy Policy as new execution steps and replaced the default RegistrationUserCreation step with my new ExtenedRegistrationUserCreation. With that the data gets stored. If I add a privacy_policy user attribute in Realm Settings → User Profile, I can also inspect it in the Keycloak Admin console.
Now to my question. After registration I send the information via webhook to a separate backend to notify it about the new user. I want to include the terms_and_conditions timestamp as well as privacy_policy timestamp with the sent message. In my webhook (which is another Keycloak SPI) I use the following code:
String termsAndConditions = user.getAttributes().getOrDefault("terms_and_conditions", List.of("")).getFirst();
String privacyPolicy = user.getAttributes().getOrDefault("privacy_policy", List.of("")).getFirst();
logger.info("consents: " + termsAndConditions + ", " + privacyPolicy);
I would expect both termsAndConditions and privacyPolicy to be non-empty, however, privacy_policy is empty. In later updates I get the privacy policy information, but its empty on the first event. Any idea why this is the case and how to fix it? Thank you for help.