Hi
I have a Keycloak realm for which I have users that are able to set up their own OTP. When they have configured their OTP, they are requested this during login. Nothing special, this is the default browser flow.
Now, I have the following requirement:
- If a user has configured OTP, they must provide it.
- Some clients, handle sensitive data. Here, OTP is required during authentication. Users will need to configure it if not already done so.
First two things that come to mind is:
- A separate authentication flow for these clients. But issues can arise since it’s an SSO. Switching applications will not enforce MFA due to the cookie.
- Use step-up authentication and define
mfa
as anACR
the client can request, which maps toLoA = 2
. This works generally, but is difficult to combine with the first requirement.
Let’s say we have the default step-up authentication flow as described in the docs:
Auth type | Requirement
---------------------------------------------------------------------------------
Cookie [x] Alternative [ ] Required [ ] Conditional
Auth Flow [x] Alternative [ ] Required [ ] Conditional
| - Level 1 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 1
| - Username Password Form [ ] Alternative [x] Required
| - Level 2 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 2
| - OTP Form [ ] Alternative [x] Required
This does not request the user an OTP by default if they have it configured, like it does in the default browser flow. A first solution would be just adding the condition in the Level 1 LoA authentication flow:
Auth type | Requirement
---------------------------------------------------------------------------------
Cookie [x] Alternative [ ] Required [ ] Conditional
Auth Flow [x] Alternative [ ] Required [ ] Conditional
| - Level 1 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 1
| - Username Password Form [ ] Alternative [x] Required
| - Conditional OTP [ ] Alternative [ ] Required [x] Conditional
| - Condition: user configured
| - OTP Form [ ] Alternative [x] Required
| - Level 2 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 2
| - OTP Form [ ] Alternative [x] Required
The problem here is that if a client immediately requests the mfa
ACR
, the user is requested to provide their OTP twice during authentication. Makes sense, since they go through both flows.
An attempted workaround is to split off the OTP form and create a conditional for either LoA = 2
or OTP configured
as alternatives. If LoA = 2
, there’s no need for an additional OTP request. If LoA = 1
, the alternative conditional is skipped and it depends on user configuration:
Auth type | Requirement
---------------------------------------------------------------------------------
Cookie [x] Alternative [ ] Required [ ] Conditional
Auth Flow [x] Alternative [ ] Required [ ] Conditional
| - Level 1 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 1
| - Username Password Form [ ] Alternative [x] Required
| - Step-Up or MFA [ ] Alternative [x] Required [ ] Conditional
| - step-up-no-mfa [x] Alternative [ ] Required [ ] Conditional
| - Level 2 LoA [ ] Alternative [ ] Required [x] Conditional
| - Condition: LoA = 2
| - OTP Form [ ] Alternative [x] Required
| - no-step-up-mfa [x] Alternative [ ] Required [ ] Conditional
| - Conditional OTP [ ] Alternative [ ] Required [x] Conditional
| - Condition: user configured
| - OTP Form [ ] Alternative [x] Required
Now this works when a client requests LoA = 2
. It also works if a client defaults to LoA = 1
and the user has OTP configured. However, it does not work if a client defaults to LoA = 1
and the user does not have OTP configured. This is because the Step-Up or MFA
step is required, but neither step-up-no-mfa
nor no-step-up-mfa
alternatives will result in success.
So I don’t really find a way to configure the requirement of “required OTP if LoA = 2 OR configured by user”. Can this be configured without custom implementations or is this scenario too “exotic”?