Skip to main content

Authentication Flow Setup

Wire the Email OTP authenticator into a Keycloak authentication flow and configure realm email settings.

Step 1 — Configure Realm Email (SMTP)

  1. Login as admin to your Keycloak installation
  2. Switch to your target realm
  3. Navigate to Realm SettingsEmail tab
  4. Fill in your SMTP server details:
FieldExample
SMTP Hostsmtp.gmail.com
SMTP Port587
From Emailnoreply@yourdomain.com
Enable StarTLS
Username / Passwordyour credentials

See Email Provider Configuration for more details on these settings.

Step 2 — Create the Authentication Flow

a) Copy the Browser Flow

  1. Navigate to Authentication
  2. Inside the Flows tab, locate the Browser flow
  3. Click the "⋮" (overflow) menu
  4. Select "Duplicate"

Keycloak Authentication Flows list — duplicate the Browser flow

  1. Name it "Browser with Email OTP"
  2. Click "Duplicate" to create the new flow

Keycloak Authentication Flows list — name the copy of Browser flow

b) Add the OTP Execution

Inside the copied flow, locate the "Browser with Email OTP Forms - Conditional 2FA" sub-flow. This is where the OTP step lives alongside username/password.

  1. Click "+" Add on the right side of the Forms row
  2. Click "Add execution"

Add execution button inside the Forms sub-flow

Choose your execution type depending on whether you want OTP for all users or only some:

Use this when: you want OTP enforced for every user, every login — no conditions.

  1. Search for and select "Email OTP"
  2. Click "Add"

Selecting Email OTP from the execution list

  1. On the "Email OTP" row, set the requirement:
RequirementBehaviour
REQUIREDEvery login always prompts for an OTP code
ALTERNATIVEOTP is offered but skipped if another factor already satisfies the flow
DISABLEDOTP step is never triggered

Setting the requirement on the Email OTP row

tip

Use REQUIRED for the strictest security. Use ALTERNATIVE only if you have other authenticators in the same flow that can substitute for OTP.

c) Bind the Flow

  1. At the top right of the flow editor, click the "Actions" menu
  2. Select "Bind flow"

Binding the new flow to the Browser flow

  1. Set Binding type to Browser flow
  2. Click "Save"

Binding the new flow to the Browser flow

After binding, the new flow will replace the default Browser flow for all browser-based logins.

Binding the new flow to the Browser flow

Resulting Flow Structure

After completing the above steps, when users log in through the browser, after successfully entering their username and password, they will be prompted to enter an OTP code sent to their email (if they have one configured and the requirement is met).

Completed authentication flow with Email OTP step

Step 3 — Configure Email OTP Settings

Click the ⚙️ Settings icon on the "Email OTP" row to open the authenticator configuration panel.

Email OTP settings panel

Settings reference

SettingDescriptionDefaultRecommended (prod)
Code lengthNumber of digits in the OTP code66
Time-to-liveSeconds before the code expires300300
Simulation modeLog codes to server logs instead of sending emailsfalsefalse
Resend cooldownSeconds a user must wait before requesting a new code3060
Max code attemptsWrong attempts allowed before the code is invalidated53
Skip setupSkip enrollment for users who already have an email addresstruetrue

Setting details

Code length

Controls how many digits are in the OTP. 6 is the industry standard and what users expect. Increasing to 8 adds marginal security at the cost of more user errors.

Time-to-live

How long (in seconds) the code remains valid after being sent. 300 seconds (5 minutes) is a good balance between security and usability. If your users report codes expiring too quickly (e.g. they check email on a slow device), increase to 600.

Simulation mode

When true, no email is sent — the OTP code is written to the Keycloak server log instead. Use this during development and local testing to avoid needing a real mail server.

docker logs keycloak | grep "SIMULATION MODE"
# ***** SIMULATION MODE ***** Email code send to test@example.com for user testuser is: 123456
warning

Never enable simulation mode in production — codes are visible in plain text in the logs.

Resend cooldown

Prevents users from spamming the "Resend code" button. The default of 30 seconds is fine for development; increase to 60 in production to reduce email abuse.

Max code attempts

After this many wrong attempts, the current code is invalidated and the user must request a new one. Lower values (e.g. 3) make brute-forcing harder but may frustrate users who mistype frequently.

Skip setup

When true, users who already have an email address on their Keycloak account skip the enrollment required action and go straight to the OTP prompt. This is the recommended setting when an admin has enforced 2FA for existing users — they are not forced through a setup wizard on their next login.

When false, every user must explicitly enroll before they can use email OTP, even if they already have an email on their account.

What's Next?