Implementing two-factor authentication in Keycloak: the factor concept, TOTP and HOTP, WebAuthn and passkeys, SMS OTP, conditional OTP, plus recovery code strategies and security policies.

In episode 22 you recorded and audited activity. Episode 23 closes the biggest gap in login security: Multi-Factor Authentication (MFA). Passwords alone are no longer enough — combining factors makes phishing attacks or password theft lose much of their value. You'll look at OTP (TOTP/HOTP), WebAuthn and passkeys, SMS, conditional OTP, down to recovery codes and their security policies.
Authentication factors are divided into three categories:
| Category | Meaning | Example |
|---|---|---|
| Something you know | Knowledge | Password, PIN |
| Something you have | Possession | OTP on a phone, hardware token |
| Something you are | Biometrics | Fingerprint, facial recognition |
MFA means combining at least two different categories. A password plus a security question doesn't count as MFA because both are "knowledge". The combination of password and OTP is the most common pattern and the easiest to implement in Keycloak.
| Aspect | TOTP | HOTP |
|---|---|---|
| Basis | Time, code changes each period | Incrementing counter |
| Devices | Google Authenticator, FreeOTP | Legacy hardware tokens |
| Synchronization | Needs an accurate clock | Can drift, needs resync |
TOTP is the standard for mobile authenticator apps; HOTP is more common in older hardware tokens.
OTP policy is set in Realm Settings → Authentication → OTP Policy: choose the type (TOTP or HOTP), number of digits, period, and algorithm (SHA1, SHA256, SHA512). The more modern the algorithm, the better. The same policy can be set via the admin CLI:
kcadm.sh update realms/myrealm -r myrealm \
-s otpPolicyType=totp \
-s otpPolicyAlgorithm=HmacSHA256 \
-s otpPolicyDigits=6 \
-s otpPolicyPeriod=30Users enable OTP through the Configure OTP required action — they scan a QR code with Google Authenticator or FreeOTP. After that, every login goes through an OTP step.
YubiKey and similar devices use the WebAuthn/FIDO2 protocol. Authentication is done by pressing a button on the device — something you "have" physically.
Windows Hello, Touch ID, and device biometric sensors are examples of platform built-in authenticators. Without additional hardware, users can still use passkeys.
WebAuthn also opens the passwordless path: users sign in with a passkey only, without any password. This is a strong option as long as its recovery is well planned.
Keycloak provides Webauthn Policy and Webauthn Passwordless Policy in Realm Settings → Authentication: set the relying party, attestation, and user verification. Device registration is done through the WebAuthn Register required action.
One-time codes sent via SMS. Practical because almost everyone has a phone.
Core Keycloak does not include a built-in SMS gateway. For SMS OTP, you need a custom authenticator (SPI) that calls an SMS service such as Twilio or a local aggregator. Revisit the custom provider mechanism from episode 21.
SMS can be intercepted through SIM swapping or carrier network gaps. Treat SMS as a second layer, not the only factor, and consider this risk when choosing a policy.
A required action is a step users must complete, such as Configure OTP. The MFA policy can be made mandatory for all users or only under certain conditions.
Conditional OTP allows OTP to be requested only when conditions are met — for example access from an unknown IP — so users who normally log in from the same place aren't bothered every time. In Keycloak, this rule is arranged by adding a condition to the authentication flow. To inspect the flow steps, use kcadm.sh get authentication/flows/browser/executions -r myrealm.
MFA strengthens security, but adds one problem: what happens if the device is lost? Since core Keycloak doesn't yet provide built-in recovery codes, you usually use a community extension or a manual recovery flow:
Decide on a recovery strategy before production — waiting for a locked-out user on day 1 is a bad way to learn.
When all layers are in place, the MFA login flow in Keycloak runs like this:
LOGIN event is recorded with the auth method details — audit evidence for episode 22.If any factor fails, the LOGIN_ERROR event is stored and the brute force detection counter (episode 24) increments.
Several recommended policies for MFA:
In episode 23, you understood MFA in Keycloak: the factor concept (knowledge, possession, biometrics), TOTP and HOTP OTP, WebAuthn with hardware keys and platform authenticators, SMS OTP with its risks, required actions and conditional OTP, recovery codes, and the security policies around them.
Key takeaways:
In the next episode (episode 24), you'll complete the defense from another side: Brute Force Protection & Security — lockout, CAPTCHA, security headers, and session and token security.