Multi-Factor Authentication Setup

Multi-Factor Authentication Setup

Multi-Factor Authentication (MFA) adds an extra layer of security by requiring users to provide multiple forms of verification. This guide covers setting up various MFA methods in Skycloak.

Overview

MFA requires users to provide two or more verification factors:

  • Something you know (password)
  • Something you have (phone, hardware token)
  • Something you are (biometrics)
ℹ️
This guide is about your own realm’s users. For MFA on your Skycloak account, the one you sign in to the dashboard with, see Choosing your MFA method. That page also covers removing or replacing your own second step: each method has its own Remove button, and if your workspace requires MFA you set up the replacement before removing the old one, since you can swap methods but never end up with none.

Available MFA Methods

Time-Based One-Time Password (TOTP)

The most common MFA method using authenticator apps.

Supported Apps:

  • Google Authenticator
  • Microsoft Authenticator
  • Authy
  • 1Password
  • LastPass Authenticator

SMS-Based OTP

Send one-time codes via SMS (requires SMS gateway configuration).

Email-Based OTP

Send one-time codes via email (requires SMTP configuration).

WebAuthn/FIDO2

Hardware security keys and platform authenticators.

Supported Devices:

  • YubiKey
  • Google Titan Security Key
  • Windows Hello
  • Touch ID / Face ID

Enabling MFA for a Realm

Basic Setup

  1. Navigate to your realm in Skycloak
  2. Go to Authentication → Required Actions
  3. Enable desired MFA methods:
    • Configure OTP for TOTP
    • WebAuthn Register for security keys
    • Update Password (if forcing password reset)

Authentication Flow Configuration

  1. Go to Authentication → Flows
  2. Select Browser flow
  3. Add execution:
    • Click Add execution
    • Select OTP Form or WebAuthn Authenticator
    • Set to Required or Alternative

TOTP Configuration

Enabling TOTP

  1. In Authentication → Required Actions
  2. Enable Configure OTP
  3. Set as Default Action if needed

TOTP Policy Settings

Navigate to Authentication → OTP Policy:

OTP Type: Time-based (totp)
OTP Hash Algorithm: SHA256
Number of Digits: 6
Look Ahead Window: 1
OTP Token Period: 30

User Enrollment Flow

  1. User logs in with username/password
  2. Prompted to set up MFA
  3. Scan QR code with authenticator app
  4. Enter verification code
  5. Save recovery codes

WebAuthn/FIDO2 Setup

Enabling WebAuthn

  1. Go to Authentication → Required Actions
  2. Enable WebAuthn Register
  3. Configure WebAuthn Policy

WebAuthn Policy

Navigate to Authentication → WebAuthn Policy:

Relying Party Entity Name: Your Company
Signature Algorithms: ES256, RS256
Relying Party ID: yourdomain.com
Attestation Conveyance Preference: none
Authenticator Attachment: platform, cross-platform
Require Resident Key: No
User Verification Requirement: preferred

Passwordless Setup

For passwordless authentication:

  1. Create new authentication flow
  2. Add WebAuthn Passwordless Authenticator
  3. Set as alternative to username/password

SMS OTP Configuration

Prerequisites

  1. Configure SMS gateway provider
  2. Set up SMS authenticator SPI

Setup Steps

  1. Install SMS authenticator extension
  2. Configure provider settings:
    Provider: Twilio/AWS SNS/Custom
    API Key: your-api-key
    API Secret: your-api-secret
    From Number: +1234567890
  3. Enable in authentication flow

Conditional MFA

Risk-Based MFA

Keycloak on its own can ask for a second factor on every login or never. The free Adaptive Risk extension asks only when a login looks unusual for that user. It scores each browser login from 0 to 100 against the user’s own past successful logins, names the reasons, and maps the score to a level:

Level Default score Typical response
Low below 30 Password only
Medium 30 to 59 OTP or WebAuthn, for users who already have one
High 60 and above Deny access

The reasons and their default weights are new_device (30), new_network (15), new_country (30), rapid_country_change (40), recent_failures (25) and unusual_hour (10). The score is their sum, capped at 100. Until a user has 3 successful logins the profile is learning: history reasons do not fire, and the login is scored as low unless there were recent failed attempts. Thresholds, weights and the number of learning logins can be changed with the gear icon on the evaluator step.

Install the extension

  1. Open your cluster in the Skycloak dashboard and go to Extensions
  2. Find Adaptive Risk and click Install
  3. Keep the pre-filled Client IP Header (CF-Connecting-IP) and Country Header (CF-IPCountry), then click Install Extension

Clear Client IP Header to use the client address Keycloak resolves itself. Clear Country Header to turn the two country reasons off. Only name headers your proxy always overwrites, because a header the client can set can be forged.

Build the flow

  1. Go to Authentication > Flows, duplicate the built-in browser flow, and remove its Conditional OTP sub-flow
  2. In the forms sub-flow, after Username Password Form, add Adaptive Risk - Evaluate (Skycloak) as Required
  3. Still in forms, add a Conditional sub-flow Deny high risk containing:
    • Condition - risk level (Skycloak), Required, gear icon: level high, match at-least
    • Deny access, Required
  4. Then add a Conditional sub-flow Step up medium risk containing:
    • Condition - risk level (Skycloak), Required, gear icon: level medium, match exactly
    • Condition - user configured, Required
    • OTP Form (or WebAuthn Authenticator), Required
  5. Bind the new flow as the realm’s Browser flow
browser (copy)
├── Cookie                                   Alternative
└── forms                                    Alternative
    ├── Username Password Form               Required
    ├── Adaptive Risk - Evaluate (Skycloak)  Required
    ├── Deny high risk                       Conditional
    │   ├── Condition - risk level (high, at-least)     Required
    │   └── Deny access                                  Required
    └── Step up medium risk                  Conditional
        ├── Condition - risk level (medium, exactly)    Required
        ├── Condition - user configured                  Required
        └── OTP Form                                     Required
⚠️
Never let a medium or high risk login enroll a new second factor. Without Condition - user configured, the OTP Form falls back to setting up a new OTP, so someone holding a stolen password could register their own authenticator and pass. Let users enroll new factors from a low-risk session only.

Keep the evaluator inside the forms sub-flow: the extension learns from a login only when the whole flow succeeds, so a login stopped at step-up or denied teaches it nothing. For recent_failures to fire, turn on Brute force detection in Realm settings > Security defenses.

Read the risk in events

Turn on Save events in Realm settings > Events. Every evaluated LOGIN event, and the LOGIN_ERROR of a denied login, carries these details:

Detail Example Meaning
risk_score 45 0 to 100
risk_level medium low, medium or high
risk_reasons new_device,new_network Reasons that fired, learning while the profile is learning, or none
risk_country CA Present when the country header gave one

The same details reach your webhooks and event exports, so you can alert on risk_level in your SIEM. If scoring ever fails, the login continues as low risk with the reason evaluation_error.

Only browser logins are scored. Logins that run no browser flow, such as the password grant or client credentials, are not stepped up. See the Extensions page for all extension options.

IP-Based MFA

Require MFA from untrusted networks:

// Require MFA outside corporate network
function authenticate(context) {
    var clientIP = context.httpRequest.getRemoteAddress();
    var trustedNetwork = "192.168.1.0/24";
    
    if (!isInNetwork(clientIP, trustedNetwork)) {
        context.challenge("otp");
        return;
    }
    context.success();
}

Recovery Options

Backup Codes

  1. Generate during MFA enrollment
  2. Store securely
  3. Single-use only
  4. Regenerate when depleted

Admin Override

Administrators can:

  • Reset user MFA
  • Temporarily disable MFA
  • Force re-enrollment

User Management

Enforcing MFA

For All Users

  1. Set MFA execution as Required in browser flow
  2. Add to default required actions

For Specific Groups

  1. Create custom authentication flow
  2. Use conditional authenticator
  3. Check group membership

For Specific Roles

// Conditional MFA for roles
if (user.hasRole("sensitive-data-access")) {
    context.challenge("otp");
}

MFA Status Monitoring

View user MFA status:

  1. Go to Users → Select user
  2. Check Credentials tab
  3. View configured MFA methods

Testing MFA

Test Scenarios

  1. New User Enrollment

    • Register new account
    • Complete MFA setup
    • Verify login with MFA
  2. Existing User Migration

    • Enable MFA requirement
    • Test forced enrollment
    • Verify graceful upgrade
  3. Recovery Flow

    • Test with backup codes
    • Admin reset scenario
    • Re-enrollment process

Best Practices

  1. Gradual Rollout

    • Start with pilot group
    • Monitor adoption
    • Address issues before full deployment
  2. User Communication

    • Provide clear instructions
    • Offer multiple MFA options
    • Support documentation
  3. Security Considerations

    • Enforce strong MFA methods
    • Regular security reviews
    • Monitor suspicious patterns
  4. Backup Methods

    • Always provide recovery options
    • Multiple MFA methods
    • Admin override procedures

Troubleshooting

Common Issues

TOTP Time Sync Issues

Problem: Invalid code errors Solution:

  • Check device time settings
  • Increase look-ahead window
  • Sync time on user device

WebAuthn Not Working

Problem: Browser doesn’t prompt for security key Solution:

  • Check HTTPS requirement
  • Verify browser compatibility
  • Check Relying Party ID

SMS Delivery Failures

Problem: Users not receiving SMS codes Solution:

  • Verify SMS gateway configuration
  • Check carrier filtering
  • Review delivery logs

Compliance Considerations

Regulatory Requirements

  • PCI DSS: MFA for admin access
  • HIPAA: MFA for PHI access
  • SOC 2: MFA for production systems
  • GDPR: Strong authentication for personal data

Audit and Reporting

Monitor MFA usage:

  • Enrollment rates
  • Authentication success/failure
  • Method preferences
  • Recovery usage

Next Steps

Last updated on