Add new email and send it from my custom authentication provider

Hi,

Keycloak fits exactly to my needs, exepts that our client wants to send OTP via email.
I added my own OTP provider, my own email template.
I didn’t found on documentation how to add and send new emails from my authentification provider.
The workflow works well excepts this points and i’m able to receive the email with otp and authenticate well:

  • Sending email block GUI until the email is sent (starting new thread doesn’t give access to keycloakSession)
    *My email is not sent in HTML format. I have created both html and text templates.
    *I dont like the way i’m processing email from my authenticator. There must be better way and better code.

    @Override
    public void authenticate(AuthenticationFlowContext context) {

      UserModel user = context.getUser();
      _currentUserName = user.getUsername();
      int otp = OtpService.generateOTP(_currentUserName);
    
      System.out.println("Generated OTP = " + otp);
      _log.info("Generated OTP = " + otp);
    //        Runnable runnable = () -> {
          Map<String, Object> attributes = new HashMap();
          FreeMarkerEmailTemplateProvider emailTemplateProvider = new FreeMarkerEmailTemplateProvider(context.getSession(), new FreeMarkerUtil());
          emailTemplateProvider.setRealm(context.getRealm());
          emailTemplateProvider.setUser(context.getUser());
          emailTemplateProvider.setAuthenticationSession(context.getAuthenticationSession());
          attributes.put("otp",otp);
          try {
    //            EmailTemplate email = emailTemplateProvider.processTemplate("emailTestSubject", Collections.emptyList(), "email-test.ftl", attributes);
    //            emailTemplateProvider.send(config, email.getSubject(), email.getTextBody(), email.getHtmlBody());
              emailTemplateProvider.send("sendOtpSubject" ,"new-otp.ftl", (Map)attributes);
          } catch (EmailException e) {
              _log.info("error while sending email: " + e.getMessage());
              e.printStackTrace();
          }
    
    Response challenge = context.form()
              .createForm(FORM_FILE_NAME);
      context.challenge(challenge);
    

Best regards.

Hi,

  • the email is sent as a multipart mime so both text and html versions are contained in the same email. It’s up to the receiver and email client to decide which one is shown as default.
  • Isn’t it normal that the UI is blocked until the email has been send as it needs to be transnational and in need of feedback in case something goes wrong. The UI is only blocked for the current person.
  • maybe you can find other examples on Github for a custom provider. I’ve made a custom provider for an event listener where is start a custom transaction by extending the extends AbstractKeycloakTransaction and then using session.getTransactionManager().enlistPrepare(… to add it to the current
1 Like

Hi Zonaut,

Thanks for taking time to respond.
I’ve fixed email html format. It’s as you said,“the email is sent as a multipart mime so both text and html versions are contained in the same email.”

My only point to resolve is the email sending that block the GUI until it is sent. In my point of view, it’s not transactionnal and my OTP form must appear immediadetly. The user can ask for sending the new OTP if the email is not sent.

I’ve tried to start new thread in charge of sending the email, but this thread doesn’t have access anymore to KeycloakSession. It’s giving the error :
Caused by: org.jboss.resteasy.spi.LoggableFailure: RESTEASY003880: Unable to find contextual data of type: org.keycloak.models.KeycloakSession

I’m not understanding something in your flow.
you sign into Keycloak with email -> you send an OTP to that email -> then show a page asking for that OTP send in the email
So you do need to send the email before showing that page to the user.

What is just blocking in your flow? Does the email take that long to send?

I’m using native login to Keycloak using username/password (the user have email on his account) => My custom OTP provider send email with OTP and show OTP form.
Because i’m using native login before my Custom OTP, I can’t send email before showing the page. I cannot modify native login provider.
Anyway, I’ve noticed that keycloak have some process that act the same… For example when you click on Forgot password? to modify password. The email sent freeze the GUI for a periode of time…

BR,

@zonaut, @fozix, we too also have similar requirement for a client wherein they want to send an OTP through email. Were u able to complete this email OTP thing? If yes can you share the codebase so that we can leverage it.

@zonaut @fozix I’m also trying to send OTP via mail. Some insight would be valuable… does not have to be public, we can pm. thanks in advance.

Keycloak already contains an OTP flow.

The original topic here was for extending OTP with his own implementation.

If you are looking for existing solutions you can do the following:

Check the code under https://github.com/keycloak/keycloak/tree/master/services/src/main/java/org/keycloak/authentication/authenticators/browser and search the Keycloak docs on https://www.keycloak.org/docs/latest/server_admin for OTP.
Also check this group for related topic https://keycloak.discourse.group/search?q=OTP

Thanks @zonaut. I was not clear enough… in my use case I need to validate the OTP via a custom UI.
I have already implemented custom Action tokens where my handler as well simply responds 200 or 400/500 and not requires the idp to host the UI.
In this case the complete token process is not practical as it happens on mobile and a simple otp is easier to type into the app, therefore the validity time is much shorter.

So my basic question is how the mobile app can validate the code via a simple call.

I did not find an example for this use case.