Use OTP validation using request

Hey guys, how’s it going?

I`m trying to create a step up process using OTP, i did it using the keykloak web interface, but i want to make it using http request.
I couldn’t find any documentation talking about it.

Thank you for your attention!

I had created a REST flow with a custom RealmResourceProvider that takes a request to setup and/or validate an OTP. If that’s what you’re after I can share what I did below. If that’s not what you’re trying to do then I hope this info is still useful to someone…

In my flow I validate the requester using their bearer token taken from the authenticated response.

AuthenticationManager.AuthResult auth = new AppAuthManager.BearerTokenAuthenticator(session).authenticate();

if (auth == null || auth.getUser() == null) {
       throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

With an authenticated session you can request a OTPCredentialProvider like this

OTPCredentialProvider otpCredentialProvider = (OTPCredentialProvider)session.getProvider(CredentialProvider.class, OTPCredentialProviderFactory.PROVIDER_ID)

If the user already has a OTP credential this snippet below will grab it.

OTPCredentialModel otpCredential = otpCredentialProvider
                .getDefaultCredential(session, realm, user);

If the user has not saved an OTP credential yet that will return a null value and you can use this instead to make a new one:

KeycloakUriInfo uriInfo = session.getContext().getUri();
TotpBean totpBean = new TotpBean(session, realm, user, uriInfo.getRequestUriBuilder());

The totpBean will contain a new secret key, the encoded secret, and the QR code byte array (as a string).

To validate a credential sent in on a request use the CredentialValidation utility class;

OTPPolicy policy = realm.getOTPPolicy();
OTPCredentialModel credentialModel = OTPCredentialModel.createFromPolicy(realm, totpSecret, "DEFAULT");
 if (!CredentialValidation.validOTP(challengeResponse, credentialModel, policy.getLookAheadWindow())) {
       throw new RuntimeException("invalid_totp");
}

To save a new OTP after the user has validate the first time there’s a utility class called CredentialHelper that you can call;

CredentialHelper.createOTPCredential(session, realm, user, challengeResponse, credentialModel)

You can forcibly delete a saved credential using the deleteCredential method on the provider;

otpCredentialProvider.deleteCredential(realm, user, otpCredential.getId());

All of this comes from code I read through in Keycloak’s github repo. I had this working successfully with Keycloak v12 and v20.

1 Like

Hey @ben.overcash, how’s it going? Thanks for your reply.

One more question, did you created this inside keykloak project or created in a external API?

I built the ResourceProvider and all the code as a Maven project and deployed it as an EJB which I deployed with the JBoss Keycloak container into our K8S cluster.

When we switched to Keycloak v20 I just built it as a jar and deployed it in the providers folder as part of the image we deploy.

In both cases, we’re not modifying the Keycloak project, just extending the official image.

I hope that answers your question.

Nice approach.

I have a question about this implementation or if you have any idea how to do it, @ben.overcash. Is there any possibility to detect if a user has changed the device he usually uses and use it to launch an OTP request to him? It is a way to avoid always asking for OTP if the user is always on the same device.

Thanks in advance

There wouldn’t be any data specifically identifying the OTP device (phone) that would be reliable to know if it’s the same device or not. You know it’s the same device only by them having access to the OTP via an authenticator app or similar.

To keep the second-factor secure the device (phone) owner would need to revoke their old OTP via the Keycloak UI or ask an admin to reset it if they lost their device and had to get a new one.

Some authenticator apps might have a recover option (such as Google and Microsoft’s Authenticator apps) which might help with OTP recovery but I haven’t looked into that much; maybe worth checking out.

Hope that helps

Wonderful Ben!

would you mind sharing the full code ? I am also trying to use TOTP validation using PrivacyIDEA authentication via Keycloak http request.

Looking for the code. Thanks in advance
-Dinesh