# Enforce OTP (TOTP) 2FA for Internal Users in Keycloak > **Goal:** Enforce OTP-based two-factor authentication (2FA) for **internal users** managed inside Keycloak in the `Digitalboard` realm, while **external users** coming from Microsoft Entra ID as Identity Provider are not prompted for OTP. --- ## Prerequisites - Admin access to the **Keycloak Admin Console** for the `Digitalboard` realm. - A running Keycloak instance (TLS termination handled by Traefik or Keycloak itself). - Microsoft Entra ID already set up as an **Identity Provider** for the realm. - Internal users stored directly in Keycloak (username/password authentication). --- ## Steps ### Step 1 — Verify External Identity Provider 1. In the **Digitalboard** realm, open the Admin Console. 2. Navigate to **Identity Providers**. 3. Confirm that **Microsoft Entra ID** is configured (OpenID Connect or SAML). 4. Ensure that external users sign in via this IdP. --- ### Step 2 — Configure OTP Policy 1. In the left-hand menu of the **Digitalboard** realm, go to **Authentication → OTP Policy** (or **Realm Settings → Security Defenses → OTP Policy**, depending on Keycloak version). 2. Configure the following: - **Type**: `totp` (time based) - **Digits**: `6` - **Period**: `30` seconds - **Algorithm**: `sha512` - **Look ahead window**: `1-2` - **Reusable token**: `off` Click **Save**. --- ### Step 3 — Copy the Browser Flow 1. Navigate to **Authentication → Flows**. 2. Locate the built-in **Browser** flow. 3. Click **Copy**. 4. Enter the new name: `browser-internal-otp`. This custom flow will handle **internal (local) user logins** for the `Digitalboard` realm. --- ### Step 4 — Add OTP Requirement 1. Open the `browser-internal-otp` flow. 2. Inside the **Browser Forms** sub-flow, locate the **Username Password Form**. 3. After it, click **Add execution** → select **OTP Form** (or **Conditional OTP** if available). 4. Set requirement to **Required**. This ensures OTP is enforced for all username/password logins (internal users). --- ### Step 5 — Enable “Configure OTP” Required Action 1. In the **Digitalboard** realm, go to **Authentication → Required Actions**. 2. Locate **Configure OTP**. 3. Ensure the status is **Enabled**. With this enabled, internal users without an OTP configured will be prompted to set it up during login. --- ### Step 6 — Bind the Flow 1. In the **Digitalboard** realm, go to **Authentication → Flows**. 2. Click the flow **browser-internal-otp** to open it. 3. In the top-right, open **Actions → Bind flow**. 4. In the dialog, choose **Browser flow** and click **Save**. > This makes `browser-internal-otp` the default Browser flow, so **internal (local) users** who log in with username/password must use OTP. **Important for external (Entra) users:** - Go to **Identity Providers → (Microsoft Entra)** and ensure **Post Login Flow / Post Broker Login Flow** is **None** (or a flow **without** OTP), so external users don't get a Keycloak OTP prompt after IdP login. --- ### Step 7 — Test the Setup 1. Log in with an **internal Keycloak user** in the `Digitalboard` realm: - After entering username and password, you should be prompted for OTP (or OTP setup if not already configured). 2. Log in with an **external Microsoft Entra user**: - You should be redirected to Entra ID for login. - After successful login, you should be signed in without an additional OTP prompt from Keycloak. --- ## Troubleshooting - **External users see OTP prompt**: Check that **Post Broker Login Flow** is not set to `browser-internal-otp`. - **Internal users not asked for OTP**: Verify that the **OTP Form** is present in `browser-internal-otp` and set to **Required**. - **Looping on OTP setup**: Ensure realm time synchronization (NTP) and correct OTP policy values. --- ## Next Steps - Roll out OTP to internal users gradually (pilot group). - Provide instructions for enrolling an authenticator app (Google Authenticator, Microsoft Authenticator, FreeOTP). - Monitor login events in the `Digitalboard` realm to confirm expected OTP usage.