Keycloak and privacyidea token authentication


As mentioned on Github, we are exploring a specific setup. In keycloak we create realms for various applications and usage. One of them is for a specific environment where we have “AD” users imported into keycloak and where we want to add “External” users to this specific realm, they are not in the AD.

We want to use our privacyidea otp backend, so that existing AD users do not require the usage of yet another token. the external users also need an otp login enabled, which then could either reside on the keycloak server itself, or because we use the privacyidea keycloak extension file (or want to use that basically ;-)) on the otp server (privacyidea).

In the future various applications will connect to the SSO environment, with different needs. Most often a set (complete or subset) of the AD needs to be imported into a group, or own realm, with potentially a wide range of external not ad-based users in it. They all need 2FA authentication as required by our policies. The above question is ideally re-usable between those specific requirements and realms (if at all possible).

I am all ears for suggestions and discussion on the topic, please let me know. I hope to be able to help my customer with that to the maximum future proof intend as possible.


Hey Remko,

you can add three executions to you flow (mark all as required).
The first is the “Username Password Form”
The second will be “PrivacyIDEA”
And the third “Conditional OTP Form”


In the privacyIDEA execution you can exclude groups.
In the Conditional OTP Form you can force or skip a role.

So if you have a group like “no2fa”, you can exclude them from privacyIDEA, but force their role to the OTP form.

Does this solution help?

Kind regards
Micha Preußer

Hi Micha,

Ah yes, I can create a group to exclude those external users from the 2fa and include them with the regular otp sequence. That would be great! I’ll give it a spin once I can actually login to the keycloak application (as we discuss on github).


As discussed on github, the privacyidea authentication does not yet work.

I get logs as:

[2019-05-16 13:40:38,697][7399][140595051525888][WARNING][privacyidea.lib.resolvers.LDAPIdResolver:323] failed to check password for ‘e533f2d8-917a-4089-976e-cc52c68c849a’/u’’: LDAPPasswordIsMandatoryError(‘password is mandatory in simple bind’,)


How do you folks always manage to create downscaled images, that can not be read?

Please provide more information to the logline. At least a version info!

First thing you should always do, take a look into the audit log.

I just made a screenshot which is rather large and uploaded that. Nothing more :-).
I will see what audit log states then.

You could have an empty username.

As mentioned, look at the audit log, which will give you an idea.
Then turn on debug log level, this will provide additional important information after the warning message.

The version of privacyidea can help to identify the running code and improve the chance to find the place in the code and the reason why you authentication breaks!

Hi Cornelius,

I will do that first thing tommorrow. I did peek already a little but the results confused me a bit. The audit log mentioned that the otppin is incorrect, where I use 1password to fillin the credentials for our simplesaml implementation towards the same privacyidea server which works instantly.

I will bump the debug level tommorrow to see what I can find, and then also report the version as you requested a few times (i did see it :-)).


So to first mention the version:

privacyidea-all/xenial,xenial,now 2.23.5-1xenial all [installed]

privacyidea-apache2/xenial,xenial,now 2.23.5-1xenial all [installed]

privacyidea-otrs/xenial,xenial,now 2.23.5-1xenial all [installed,automatic]

privacyidea-radius/xenial,xenial,now 2.23.5-1xenial all [installed,automatic]

privacyideaadm/xenial,xenial,now 2.15.1-1xenial all [installed]

python-privacyidea/xenial,xenial,now 2.23.5-1xenial all [installed,automatic]

And the audit message without bumping the level:

61040 5/17/19 08:00:44 POST /validate/check 0 [my user ] [realm] [resolver] keycloak-ip wrong otp pin OK OK machinename

and with bumped loglevels this is likely the issue (As reported by keycloak as well):

[2019-05-17 08:04:56,704][4889][139836691494656][DEBUG][privacyidea.lib.resolvers.LDAPIdResolver:823] Added ADhost, None, False to server pool.
[2019-05-17 08:04:56,704][4889][139836691494656][DEBUG][privacyidea.lib.resolvers.LDAPIdResolver:302] Authtype: u’Simple’
[2019-05-17 08:04:56,704][4889][139836691494656][DEBUG][privacyidea.lib.resolvers.LDAPIdResolver:303] user : u’myDNString’
[2019-05-17 08:04:56,707][4889][139836691494656][WARNING][privacyidea.lib.resolvers.LDAPIdResolver:323] failed to check password for ‘e533f2d8-917a-4089-976e-cc52c68c849a’/u’MyDNString’: LDAPPasswordIsMandatoryError(‘password is mandatory in simple bind’,)
[2019-05-17 08:04:56,708][4889][139836691494656][DEBUG][privacyidea.lib.resolvers.LDAPIdResolver:324] Traceback (most recent call last):
File “/usr/lib/python2.7/dist-packages/privacyidea/lib/resolvers/”, line 315, in checkPass
r = l.bind()
File “/usr/lib/python2.7/dist-packages/ldap3/core/”, line 536, in bind
request = bind_operation(self.version, self.authentication, self.user, self.password, auto_encode=self.auto_encode)
File “/usr/lib/python2.7/dist-packages/ldap3/operation/”, line 59, in bind_operation
raise LDAPPasswordIsMandatoryError(‘password is mandatory in simple bind’)
LDAPPasswordIsMandatoryError: password is mandatory in simple bind