Direct Grant prompt for OTP if configured

Using the direct grant flow, if I submit the correct username and password and OTP is not configured for the user, then the flow is successful.

If I submit the correct username and password but omit the OTP when this is configured I get a 401, but I cannot see a way of determining that an OTP was required, rather than that the supplied credentials were wrong.

Is it possible to do this in direct grant flow? i.e. have an application try the direct grant flow, and then KeyCloak return a different error that implies an OTP is required?

It doesn’t make sense to have OTP in the direct grant flow. There is no room for OTP. But other MFA can be used, e.g. client cert.

A prompt is not what I meant, but some feedback that says an OTP code is required for the current user would be useful. After all, you can log in to direct grant with an OTP code as well

Actually, it does make sense to use TOTP with “Direct Access Grant”, Keycloak supports this and I personally use this feature quite often.

Just add parameter named “totp” to your request with the one time password as a value.

Hint: oathtool can help you with generating otp from the command line / script.

1 Like

Yes agreed it makes sense and I too am using it. My problem is that not all of my users have OTP devices enabled, and so the client side logic to ask the user for a value for the totp parameter has no way of knowing, as both ‘missing totp parameter’ and ‘incorrect username/password’ result in a 401.

I can’t assume every 401 is a prompt for an OTP code. So how do I know in direct grant flow that I need to send a totp parameter for a particular user?

I am afraid that you can’t do it with no changes in Keycloak code.

Maybe simpler and safer solution is to ask a user to supply OTP regardless it is configured or not?
Adding a hint “leave blank if OTP is not configured” would probably increase users’ awareness of existance of TOTP which is a good sideeffect of the solution.

I suspected as much, thanks for the confirmation.

The user experience isn’t ideal as I can’t think of an example of a similar system that would do the same. Expert users wouldn’t be fazed but the rest would certainly risk being put off.

Changing the response status in the actual KeyCloak code is a consideration, but there are security risks I don’t have an easy answer to.

@richjyoung if you still need a solution, the following script authenticator added to the “Direct Grant” flow -> “Direct Grant - Conditional OTP” (REQUIRED; between “Condition - User Configured” and “OTP”) will return “OTP missing” along with 401 when the username and password are correct, but otp is configured for the user and missing.

AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
Response = Java.type("javax.ws.rs.core.Response");
ResponseStatus = Java.type("javax.ws.rs.core.Response.Status");

function authenticate(context) {
if(null === context.getHttpRequest().getDecodedFormParameters().getFirst("otp")){
    context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, Response.status(ResponseStatus.UNAUTHORIZED).entity("{\"error\": \"invalid_grant\",\"error_description\": \"OTP missing\"}").type("application/json").build());
    return;
}
context.success();

}