Skip to content

Keycloak Security Hardening

Skycloak runs, patches and backs up your Keycloak for you, but the settings that decide how hard your realms are to attack belong to you. This guide walks through the realm settings that matter most, gives recommended values for each, and ends with a checklist you can use to audit a realm on your own.

This guide covers:

  • Security headers: the HTTP headers Keycloak sends with its login and account pages
  • Password policy: length, complexity, history and hashing for realm users
  • Brute force detection: locking accounts after repeated failed logins
  • MFA enforcement: requiring a second factor for your dashboard team and for your realm users
  • Security audit checklist: yes/no checks to run on every realm

Each section applies to one realm. Repeat the steps for every realm your applications sign users in to.

Most steps happen in the Keycloak Admin Console. To open it:

  1. Select your cluster in the Skycloak dashboard
  2. On the Overview page, click Open admin console. When the Admin Console SSO card on that page is on, you are signed in with your Skycloak account
  3. Pick your realm from the realm selector in the top left of the Admin Console

The Skycloak dashboard also summarises a realm’s security settings. Open your cluster, click a realm in the realms grid, and look at the Security posture card. It shows email verification, self-registration, brute-force protection, password policy, session and token lifetimes, passkeys and MFA enforcement, with an amber dot on each row that needs attention. Its action buttons open the matching recipe or the Admin Console.

Keycloak adds a set of browser security headers to every page it serves for a realm: the login page, the account console and the error pages. They tell the browser whether the page may be framed, which content it may load, and whether it must only be reached over HTTPS.

  1. In the Admin Console, select your realm
  2. Go to Realm settings > Security defenses
  3. Open the Headers tab
  4. Edit the values and click Save

Changes apply to the next page Keycloak serves. No restart is needed.

Header Keycloak default Recommendation
X-Frame-Options SAMEORIGIN Keep SAMEORIGIN. Only another Keycloak page may frame the login page, which blocks clickjacking.
Content-Security-Policy frame-src 'self'; frame-ancestors 'self'; object-src 'none'; Keep the default. Add origins to frame-ancestors only if your application frames Keycloak pages (see below).
Content-Security-Policy-Report-Only empty Leave empty, or use it to test a stricter policy before you enforce it.
X-Content-Type-Options nosniff Keep nosniff. It stops browsers from guessing a file’s type.
X-Robots-Tag none Keep none. Search engines should not index your login pages.
HTTP Strict Transport Security (HSTS) max-age=31536000; includeSubDomains Keep the default. Browsers then refuse to reach your sign-in host over plain HTTP for a year.
Referrer Policy no-referrer Keep no-referrer. Login URLs carry state you do not want to leak to other sites.

Older Keycloak versions also show X-XSS-Protection. Modern browsers ignore it, so its value no longer matters.

The defaults are already a strong baseline. The most common reason to change them is not to tighten them but to loosen them by mistake while debugging an iframe problem, so check them whenever a realm has been edited by hand.

Some setups load Keycloak pages inside an iframe, for example the silent check-sso flow in keycloak-js, or a login page embedded in your own application. With the default headers the browser blocks the frame, because your application is on a different origin from your sign-in host.

To allow it for one origin without opening it to every site:

  1. In Content-Security-Policy, add your application’s origin to frame-ancestors, for example:

    frame-src 'self'; frame-ancestors 'self' https://app.example.com; object-src 'none';
  2. Clear X-Frame-Options. It cannot list a specific origin, and browsers that support frame-ancestors use the CSP value instead

  3. Click Save

Never use frame-ancestors * or remove the CSP entirely. That lets any site frame your login page.

If your realm is served from a custom domain, the HSTS header applies to that hostname and, with includeSubDomains, to hostnames below it. Only add preload if you control the whole parent domain, serve every subdomain over HTTPS, and intend to submit it to the browser preload list, because preloading is hard to undo.

Keycloak sets no password policy on a new realm, so any password a user types is accepted. If your users sign in with passwords, set a policy.

This policy follows current guidance (NIST SP 800-63B): favour length, block obvious choices, and do not force regular rotation.

Policy Value Why
Minimum length 12 Length is the strongest single factor against guessing.
Not username on Blocks the username as the password.
Not email on Blocks the email address as the password.
Not recently used 5 A user cannot cycle back to one of their last five passwords.
Hashing algorithm leave at the default Keycloak picks a strong algorithm for the version your cluster runs.
Hashing iterations leave at the default Lowering it makes stolen hashes cheaper to crack.

The resulting policy string, as Keycloak stores it, is:

length(12) and notUsername and notEmail and passwordHistory(5)

If a compliance framework you follow requires character classes, also add Uppercase characters, Lowercase characters, Digits and Special characters, each set to 1. Leave Expire password off unless a framework requires it: forced rotation tends to produce weaker, predictable passwords.

  1. In the Admin Console, select your realm
  2. Go to Authentication and open the Policies tab
  3. Open the Password policy sub-tab
  4. Click Add policy and add Minimum length, then set it to 12
  5. Add Not username, Not email and Not recently used, and set Not recently used to 5
  6. Click Save

Back in the Skycloak dashboard, the realm’s Security posture card now lists the policy on the Password policy row.

A new policy is checked when a password is set or changed. Existing passwords keep working until then. To make everyone pick a compliant password now, add the Update Password required action to users from Users > select a user > Required user actions. Each user is asked for a new password at their next login.

If you change the hashing algorithm or iterations, Keycloak re-hashes each password the next time that user signs in. Nobody is locked out.

Brute force detection stops password guessing by locking an account after repeated failed logins. Keycloak turns it off on a new realm.

Setting What it controls
Brute Force Mode Off, temporary lockout, permanent lockout, or permanent lockout after a number of temporary ones
Max login failures Failed attempts before the account is locked
Wait increment How long the first lockout lasts. Each further lockout adds this amount again
Max wait The longest a temporary lockout can last
Failure reset time How long after the last failure the failure count goes back to zero
Quick login check milliseconds Two failed attempts closer together than this count as an automated attack
Minimum quick login wait How long the account is locked after a quick-login failure
Maximum temporary lockouts In the permanent-after-temporary mode, how many temporary lockouts happen before the permanent one
Setting Value
Brute Force Mode Lockout temporarily
Max login failures 5
Wait increment 1 minute
Max wait 15 minutes
Failure reset time 12 hours
Quick login check milliseconds 1000
Minimum quick login wait 1 minute

With these values a password guesser gets five tries, then waits at least a minute, with the wait growing up to 15 minutes. That makes online guessing impractical while a real user who mistypes their password is only slowed down.

  1. In the Admin Console, select your realm
  2. Go to Realm settings > Security defenses
  3. Open the Brute force detection tab
  4. Set Brute Force Mode to Lockout temporarily
  5. Enter the recommended values above
  6. Click Save

The realm’s Security posture card in the Skycloak dashboard now shows Brute-force protection as on, with the failure count and lockout time.

Depending on your Keycloak version and realm settings, a locked user may see the same “Invalid username or password” message as any failed login, or a message saying the account is temporarily disabled. To unlock someone before the wait ends, go to Users and select the user. While the user is locked, the user details page shows a Temporarily locked switch that is on. Turn it off to unlock the user. After a permanent lockout, check the same page and turn Enabled back on if the user shows as disabled.

Brute force detection also feeds the free Adaptive Risk extension’s recent_failures signal. See Risk-Based MFA.

There are two places to require a second factor, and a hardened setup uses both.

Workspace MFA enforcement protects the people who manage your clusters. When it is on, every member of your workspace has to set up an authenticator app or a security key before they can use the dashboard. Because Admin Console SSO signs people in with their Skycloak account, the same second factor also protects access to your Keycloak Admin Console.

  1. In the Skycloak dashboard, go to Settings > Security
  2. On the Multi-Factor Authentication card, click Require MFA
  3. In the confirmation dialog, click Enforce MFA

The card then shows Required. Members who have not set up MFA get an email and are asked to set it up at their next login.

Whether workspace MFA enforcement is included depends on your plan. If your plan does not include it, the Multi-Factor Authentication card shows a lock tag instead of the Require MFA button, with a link to view pricing. See MFA Enforcement for the member experience.

Realm MFA protects the users who sign in to your applications. The quickest way to turn it on is the Multi-factor authentication (MFA) recipe:

  1. In the Skycloak dashboard, go to Recipes and choose Multi-factor authentication (MFA), or click the action on the MFA enforcement row of a realm’s Security posture card
  2. Pick the second factors to offer: Authenticator app (TOTP), Security key (WebAuthn second factor), or both
  3. Turn on Enforce for all users to prompt every user, including existing ones, to set up a second factor at their next login
  4. Click Enable & enforce

If you leave Enforce for all users off, MFA is available but optional: users can add a second factor from the Account Console. For most realms, enforce MFA at least for administrators and for any user who can reach sensitive data.

The Multi-Factor Authentication Setup guide covers the rest: OTP and WebAuthn policies, risk-based MFA that only asks when a login looks unusual, enforcing MFA for specific groups or roles, and recovery.

Run this checklist on each realm after initial setup and again whenever someone has changed realm settings by hand. Every item should be answered Yes. For each No, the section above tells you how to fix it.

Check Where to look
Is MFA enforcement on for your workspace? Skycloak dashboard > Settings > Security > Multi-Factor Authentication shows Required
Does every workspace member still need access, with the lowest role that works? Skycloak dashboard > Team
Is Admin Console SSO used for Admin Console access, rather than shared admin passwords? Skycloak dashboard > your cluster > Overview > Admin Console SSO card
Check Where to look
Is X-Frame-Options SAMEORIGIN, or empty only because CSP frame-ancestors lists specific origins? Admin Console > Realm settings > Security defenses > Headers
Does Content-Security-Policy contain frame-ancestors without a * and object-src 'none'? Admin Console > Realm settings > Security defenses > Headers
Is X-Content-Type-Options nosniff? Admin Console > Realm settings > Security defenses > Headers
Is HTTP Strict Transport Security (HSTS) set with a max-age of at least 31536000? Admin Console > Realm settings > Security defenses > Headers
Is Referrer Policy no-referrer? Admin Console > Realm settings > Security defenses > Headers
Check Where to look
Does the realm have a password policy? Skycloak dashboard > realm page > Security posture > Password policy
Is Minimum length at least 12? Admin Console > Authentication > Policies > Password policy
Are Not username and Not email set? Admin Console > Authentication > Policies > Password policy
Is Not recently used set to 5 or more? Admin Console > Authentication > Policies > Password policy
Are Hashing algorithm and Hashing iterations absent from the policy list, so Keycloak uses its own defaults? Admin Console > Authentication > Policies > Password policy
Check Where to look
Is brute-force protection on? Skycloak dashboard > realm page > Security posture > Brute-force protection
Is Brute Force Mode set to Lockout temporarily (or a permanent mode you chose on purpose)? Admin Console > Realm settings > Security defenses > Brute force detection
Is Max login failures 10 or fewer? Admin Console > Realm settings > Security defenses > Brute force detection
Is Max wait 15 minutes or longer? A longer wait slows guessing more, so a higher value is stricter. Admin Console > Realm settings > Security defenses > Brute force detection
Check Where to look
Is MFA enforced for the realm, or at least for administrators and privileged users? Skycloak dashboard > realm page > Security posture > MFA enforcement
Is email verification required on sign-up? Skycloak dashboard > realm page > Security posture > Email verification
Is self-registration off, unless your application needs open sign-up? Skycloak dashboard > realm page > Security posture > Self-registration
Do session idle and token lifetimes match your policy? Skycloak dashboard > realm page > Security posture > Session & tokens, and the Session Timeouts guide
Check Where to look
Are login events saved, so failed logins and lockouts can be reviewed? Admin Console > Realm settings > Events > User events settings > Save events
Are admin events saved, so configuration changes can be traced? Admin Console > Realm settings > Events > Admin events settings > Save events
Are security events sent to your SIEM or alerting? Skycloak dashboard > Events and webhooks, and the SIEM Integration guide