Zum Inhalt springen

Keycloak Security Hardening

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

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
  • Cluster Security page: geo blocking, IP access control, rate limiting and CAPTCHA in front of your cluster
  • Security audit checklist: yes/no checks to run on every realm

Each realm section applies to one realm. Repeat the steps for every realm your applications sign users in to. The Security page protections apply to a whole cluster, except CAPTCHA, which you turn on per realm.

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.

The realm settings above control what Keycloak does with a request. The cluster’s Security page in the Skycloak dashboard adds protections that act before a request reaches Keycloak: blocking countries, limiting paths to known networks, capping request rates, and putting a CAPTCHA challenge on the login page.

Each protection is a paid add-on. You buy it once for your workspace in the Skycloak dashboard under Settings > Add-ons, in the Security add-ons section.

Protection What it needs
Geo blocking The Geo-blocking add-on. Available on the Launch plan and above, not on the Developer plan.
IP access control The IP Access Control add-on.
Rate limiting The Advanced Rate Limiting add-on. Available on the Launch plan and above, not on the Developer plan.
CAPTCHA The CAPTCHA Protection add-on. Available on the Launch plan and above, not on the Developer plan.

Until your workspace has the add-on, the matching card on the Security page shows a lock and a View add-ons link, and its switch cannot be turned on.

  1. Select your cluster in the Skycloak dashboard
  2. Click Security in the cluster navigation
  3. Stay on the Configuration tab. Each protection has its own card with an Enabled / Disabled switch
  4. After changing a card, click Save Configuration at the bottom of the page

Changes take up to a minute to apply. Your cluster keeps serving sign-ins during that time with the previous settings. Reset Changes discards edits you have not saved yet. Only cluster administrators can change these settings; other members see them read-only.

The Analytics and Logs tabs on the same page show the requests these protections blocked. Check them after every change to make sure real users are not being turned away.

Geo blocking allows or blocks requests by the country they come from.

  1. On the Geo-blocking card, turn the switch on
  2. Under Access Mode, pick Whitelist to allow only the selected countries, or Blacklist to block the selected countries and allow the rest
  3. Add countries from Select a country…. You need at least one
  4. Click Save Configuration

Whitelist is the stricter mode and suits applications whose users are all in known countries. Overseas territories have their own country codes, so whitelisting France (FR) does not cover Réunion (RE) or Guadeloupe (GP). Add every territory you want to allow.

IP access control restricts a path to the IP addresses and CIDR ranges you list. Requests to that path from anywhere else are refused. A common use is keeping the Admin Console reachable only from your office or VPN while sign-in stays public.

  1. On the IP Access Control card, turn the switch on
  2. Under Add New Path Rule, enter a Path Pattern that starts with /, for example /admin/* for the Admin Console or /realms/master/* for the master realm
  3. Add one or more addresses under Allowed IP Addresses, for example 203.0.113.10, and click + after each
  4. Add one or more ranges under Allowed CIDR Ranges, for example 10.8.0.0/24, and click + after each
  5. Add a Description (optional) that says why the rule exists, for example Admin console access
  6. Click Add Path Rule, and repeat for other paths
  7. Click Save Configuration

Each rule needs at least one IP address or CIDR range. If the card is on with no rules, the page refuses to save until you add a rule or turn the card off.

Rate limiting caps how many requests per minute the cluster accepts. There are three kinds of limit, and you can combine them:

Limit What it caps Starting value
Global Rate Limit (RPM) Requests per minute from all sources combined. 0 turns it off. 5000 to 10000
Per-IP Rate Limit (RPM) Requests per minute from a single client IP, counting API and login requests only. 0 turns it off; otherwise the minimum is 60. 200
Endpoint-Specific Limits Requests per minute to one exact path. 50 to 100 on login and token paths
  1. On the Rate Limiting card, turn the switch on
  2. Enter a Global Rate Limit (RPM) and a Per-IP Rate Limit (RPM)
  3. To limit a single path, click Add Endpoint, enter the Endpoint Path and its Requests Per Minute (RPM), and click Add Limit. For example, /realms/myrealm/protocol/openid-connect/token at 100
  4. Click Save Configuration

At least one limit must be set while the card is on. Endpoint paths must start with / and be exact paths: wildcards such as /realms/* are not accepted.

Start with generous limits, watch the Analytics tab for a week or two, then lower them towards your real peak traffic. Rate limiting works alongside brute force detection: rate limits slow down floods of requests from any source, while brute force detection protects individual accounts.

CAPTCHA Protection adds a Cloudflare Turnstile challenge to a realm’s login, which stops automated sign-in and sign-up attempts. It runs as its own step in the realm’s login flow, so it works with managed and custom themes alike and you have no theme files to edit.

Enabling CAPTCHA requires the CAPTCHA Protection add-on, and it restarts your cluster’s Keycloak instances. Plan it for a quiet period: users see a brief sign-in interruption while the instances come back up.

  1. On the CAPTCHA Protection card, turn the switch on
  2. Under Select Realm, choose the realm to protect. Only realms with a login theme installed are listed. If you see No realms with themes found, install a theme on the realm first
  3. Under Protected Domains, check the domains. Your cluster’s own domains are protected automatically. To protect a custom domain, choose it from Select a custom domain to protect…. The domain must be verified and have active SSL
  4. Click Save Configuration
  5. In the Restart instances? dialog, click Apply and restart

A progress window follows the restart. Protection is enforced once the instances are back up. Turning CAPTCHA off again also restarts the instances. Changing the protected realm or domains while CAPTCHA stays on does not.

Each cluster you protect uses one unit of the CAPTCHA Protection add-on. If saving fails with a message that all purchased units are allocated, increase the add-on quantity under Settings > Add-ons.

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

Skip the rows for a protection your workspace has not added.

Check Where to look
Is Geo-blocking on, with the countries you meant to allow or block, including any overseas territories? Skycloak dashboard > your cluster > Security > Configuration > Geo-blocking
Is the Admin Console path (/admin/*) limited to your office or VPN addresses? Skycloak dashboard > your cluster > Security > Configuration > IP Access Control
Does every IP access rule have a description that says why it exists, and do all its addresses still belong to you? Skycloak dashboard > your cluster > Security > Configuration > IP Access Control
Is Rate Limiting on, with a Per-IP Rate Limit (RPM) set? Skycloak dashboard > your cluster > Security > Configuration > Rate Limiting
Do your login and token paths have their own endpoint-specific limits? Skycloak dashboard > your cluster > Security > Configuration > Rate Limiting > Endpoint-Specific Limits
Is CAPTCHA Protection on for every realm with public sign-in or sign-up? Skycloak dashboard > your cluster > Security > Configuration > CAPTCHA Protection
Are your custom sign-in domains listed as Protected, with none marked as needing attention? Skycloak dashboard > your cluster > Security > Configuration > CAPTCHA Protection > Protected Domains
Have you checked the blocked requests for real users being turned away since the last change? Skycloak dashboard > your cluster > Security > Analytics and Logs
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