The Keycloak Security Hardening Checklist
Last updated: November 2026
Hardening Keycloak comes down to a focused set of changes across seven areas: enforce TLS and correct proxy/hostname settings, lock down the admin console and master realm, tune brute-force protection and token/session lifetimes, require MFA for privileged users, and enable audit logging. Keycloak’s defaults are deliberately permissive, they are designed to get developers running quickly, not to protect production workloads. Working through this checklist before go-live will close the most common attack surfaces.
This checklist targets Keycloak 26.x on the Quarkus distribution. If you are still on the WildFly-based distribution, migrate, WildFly is no longer supported. For broader production readiness beyond security, see our Keycloak production-ready checklist. Many items below map directly to controls in the OWASP Application Security Verification Standard (ASVS).
1. Transport and hostname
Getting TLS and hostname configuration right is not optional. Misconfigured proxy headers or a missing HTTPS enforcement is frequently the first thing an attacker probes.
Enforce HTTPS everywhere.
Set KC_HTTP_ENABLED=false (or http-enabled=false in keycloak.conf) to disable the plaintext listener. Your load balancer handles TLS termination; Keycloak must be told to generate HTTPS redirect URIs and self-referential links.
Set KC_HOSTNAME (or hostname) explicitly.
Without this, Keycloak infers its public URL from the request, producing incorrect token issuers and broken redirects behind a proxy. Set KC_HOSTNAME=https://auth.example.com and KC_HOSTNAME_ADMIN=https://auth-admin.example.com if the admin console uses a separate hostname.
Configure KC_PROXY_HEADERS correctly.
In Keycloak 26.x, KC_PROXY_HEADERS replaces the older KC_PROXY variable. Set it to forwarded (RFC 7239) or xforwarded (X-Forwarded-*), matching what your load balancer sends. A mismatch causes wrong client IPs and self-referential URL errors; leaving it unset when a proxy is present opens a header-injection risk.
Add HSTS at the proxy layer.
Keycloak does not set Strict-Transport-Security itself. Add max-age=31536000; includeSubDomains at the terminating proxy to prevent protocol downgrade attacks.
Checklist items:
- [ ]
KC_HTTP_ENABLED=falsein production - [ ]
KC_HOSTNAMEset to the public HTTPS URL - [ ]
KC_PROXY_HEADERSmatches the proxy’s forwarding header style - [ ] HSTS header configured at the reverse proxy
2. Admin console and master realm
The Keycloak admin console is effectively a root-level control plane for every realm. Treating it with the same access controls you would apply to a database root account is not an exaggeration.
Restrict admin console network exposure.
The admin console and Admin REST API must not be reachable from the public internet. Use path-based routing to serve /admin/* only from an internal network segment, or expose the admin interface on a dedicated port via http-management-port in Keycloak 26.x and firewall it from external traffic.
For a detailed walkthrough of master-realm specific risks and mitigations, see our post on how to secure your Keycloak master realm.
Never use the master realm for application authentication.
The master realm exists to administer other realms. Application users should live in dedicated realms. If an application credential is compromised in a shared master realm, the blast radius includes every realm in the instance.
Harden the master-realm admin account.
The bootstrap admin account (often admin) should be renamed or disabled and replaced with a named account tied to a real identity. Enable MFA on all accounts with admin roles. Use per-realm admin accounts with realm-admin roles rather than the top-level admin role wherever possible.
Audit and rotate service accounts.
Every client with Service Accounts Enabled carries a machine identity. Review them quarterly, remove inactive ones, and ensure each has only the roles it actually uses. Broad roles granted during development are easy to forget and expensive to discover post-incident.
Checklist items:
- [ ] Admin console unreachable from public internet
- [ ] Master realm used only for realm administration, not applications
- [ ] Bootstrap admin account replaced with named MFA-protected accounts
- [ ] Service account credentials rotated and scoped to least privilege
3. Brute-force protection and credentials
Keycloak ships with brute-force protection disabled. That means a default installation has no lockout policy, no temporary account suspension, and no alert when an account is being attacked.
Enable brute-force detection.
Go to Realm Settings > Security Defenses > Brute Force Detection and toggle it on. Set Max Login Failures (10 is a common starting point), Wait Increment, and a Max Wait ceiling of 15-30 minutes. Note that the built-in protection tracks failures per username, not per IP. Our post on Keycloak’s IP-based brute-force protection gap explains why WAF-layer rate limiting is a necessary complement.
Enforce a password policy.
In Authentication > Policies > Password Policy, add: minimum length of 12 characters, at least one uppercase and one digit, history count of 5, plus notUsername and notEmail to block trivially guessable passwords.
Require MFA for privileged access, and consider it for all users.
Keycloak supports TOTP (Google Authenticator, Authy) and WebAuthn (passkeys, security keys) out of the box. For internal applications and admin access, require it via an Authentication Flow that marks OTP or WebAuthn as Required rather than Optional. For consumer-facing applications, consider Alternative to preserve UX. Skycloak’s multi-factor authentication feature is built directly on these Keycloak flows and can be enabled per-realm without custom configuration.
Checklist items:
- [ ] Brute-force detection enabled with lockout thresholds
- [ ] Proxy/WAF-layer rate limiting for distributed attacks
- [ ] Password policy enforced (length, complexity, history)
- [ ] MFA required for admin accounts; evaluated for all application users
4. Tokens and sessions
Token and session settings are the area where developers most often leave insecure defaults in place because the defaults “work”, they just work in a way that is unnecessarily permissive.
Shorten access token lifespan.
Keycloak’s default access token lifespan is 5 minutes (accessTokenLifespan in Realm Settings > Tokens), reasonable for most applications. If your realm was bumped to 30 or 60 minutes during development, reduce it back. Short-lived tokens limit the damage from interception.
Enable refresh-token rotation.
In Realm Settings > Tokens, enable Revoke Refresh Token. Each use of a refresh token then invalidates it and issues a new one, so a replayed token fails immediately. See our Keycloak refresh token rotation guide for implementation details.
Tune SSO session idle and max.
The defaults (SSO Session Idle: 30 minutes, SSO Session Max: 10 hours) control how long a browser session stays alive at the Keycloak level. For sensitive applications, reduce SSO Session Idle to 15 minutes and SSO Session Max to 4-8 hours. For high-security contexts (finance, healthcare), consider step-up authentication for sensitive operations rather than relying on session duration alone.
Disable Full Scope Allowed on clients.
Every new client has Full Scope Allowed enabled by default, meaning access tokens carry all realm and client roles. Disable it and add only the scopes the client actually needs via the Client Scopes tab. This limits the damage from a compromised token.
Checklist items:
- [ ] Access token lifespan at 5 minutes or less
- [ ] Refresh token rotation (
Revoke Refresh Token) enabled - [ ] SSO Session Idle and Max set appropriate to application sensitivity
- [ ]
Full Scope Alloweddisabled on all production clients
5. Client configuration
Each registered client is an authentication surface. Misconfigured clients account for a disproportionate share of OAuth 2.0 vulnerabilities in practice.
Use confidential clients wherever possible.
Server-side applications should use Client Authentication: On, which requires a client secret for token exchange. Public clients (SPAs, native apps) cannot hold a secret, so they require the additional protections below.
Lock down redirect URIs to exact values.
Wildcard redirect URIs (https://app.example.com/*) enable open-redirect and authorization-code interception attacks. Set exact values: https://app.example.com/callback. Keycloak rejects requests that do not match exactly. Apply the same precision to Web Origins.
Require PKCE for public clients.
In the client’s Advanced settings, set Proof Key for Code Exchange Code Challenge Method: S256. PKCE prevents authorization code interception where a client secret cannot be kept confidential.
Apply least-privilege scopes.
Disable Full Scope Allowed and add only required scopes per client. Review the Client Scopes tab and remove anything unused. The offline_access scope grants long-lived offline refresh tokens and should be explicitly granted only to clients that require it.
Checklist items:
- [ ] Server-side clients use confidential flow with client authentication
- [ ] Redirect URIs are exact, no wildcards
- [ ] PKCE (
S256) enabled for public clients - [ ]
offline_accessgranted only to clients that require it
6. Auditing and monitoring
A security hardening exercise is incomplete without a detection layer. Keycloak generates detailed event logs for logins and admin operations; the question is whether those logs reach a system where someone will look at them.
Enable login and admin events.
In Realm Settings > Events > Event Listeners, confirm jboss-logging (or log) is active. Enable login event saving with 30-90 day retention. In the Admin Events tab, enable event saving and check Include Representation to capture the full payload of changes, without this, you know a client was modified but not how. For a complete reference of available events and how to query them, see our Keycloak auditing and event logging guide.
Forward events to a SIEM or log aggregator.
Keycloak’s built-in event storage is a database table, not a security monitoring system. Implement a custom EventListenerProvider (or use the community Elasticsearch listener) to forward events to your SIEM, Datadog, or Splunk instance. Key events to alert on: LOGIN_ERROR with INVALID_USER_CREDENTIALS, repeated BRUTE_FORCE events, ADMIN.* events outside business hours, and CLIENT_DELETE or REALM_UPDATE operations. Skycloak’s audit logs feature provides a managed event pipeline so you do not have to build or maintain this forwarding infrastructure.
Establish a baseline and alert on anomalies.
Create alerts for: more than N failed logins per user in 5 minutes, admin console logins from unrecognized IPs, token refresh activity at unusual hours, and service account authentications that deviate from their normal pattern.
Checklist items:
- [ ] Login events enabled with 30-90 day retention
- [ ] Admin events enabled with representation capture
- [ ] Events forwarded to SIEM or log aggregation platform
- [ ] Alerts configured for failed logins, brute force, and off-hours admin access
7. Platform and operational security
Keep Keycloak up to date.
Target: minor version updates within 30 days, security-only patches within 7 days. Subscribe to Keycloak Security Advisories on GitHub.
Database least privilege.
The database user needs only SELECT, INSERT, UPDATE, DELETE on Keycloak’s schema, no DROP, CREATE, or GRANT. Use a dedicated schema, not a shared database with application data.
Never store secrets in plaintext.
Client secrets, database passwords, and SMTP credentials must not live in version-controlled files or .env files baked into container images. Use a secrets manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) or Kubernetes Secrets with encryption at rest.
Disable unnecessary features.
If you do not use LDAP/AD federation, disable the User Storage SPI. If users should not self-register, disable it at Realm Settings > Login > User Registration: Off.
Checklist items:
- [ ] Keycloak version current; patch cadence defined
- [ ] Database user scoped to least-privilege permissions
- [ ] All secrets stored in a secrets manager, not plaintext files
- [ ] User self-registration disabled if not required
Consolidated hardening checklist
| Area | Item | Admin Path / Config |
|---|---|---|
| Transport | Disable HTTP listener | KC_HTTP_ENABLED=false |
| Transport | Set public hostname | KC_HOSTNAME=https://auth.example.com |
| Transport | Configure proxy headers | KC_PROXY_HEADERS=xforwarded or forwarded |
| Transport | Add HSTS at proxy | Reverse proxy config |
| Admin | Restrict admin console to internal network | Firewall / path routing |
| Admin | Never use master realm for applications | Realm design |
| Admin | MFA on all admin accounts | Realm Settings > Authentication |
| Admin | Rotate and scope service accounts | Clients > Service Account Roles |
| Credentials | Enable brute-force detection | Realm Settings > Security Defenses |
| Credentials | Enforce password policy | Authentication > Policies |
| Credentials | Require MFA for privileged users | Authentication > Flows |
| Tokens | Access token lifespan to 5 min or less | Realm Settings > Tokens |
| Tokens | Enable refresh-token rotation | Realm Settings > Tokens > Revoke Refresh Token |
| Tokens | Tune SSO session idle and max | Realm Settings > Tokens |
| Tokens | Disable Full Scope Allowed | Clients > Client Scopes |
| Clients | Confidential flow for server-side clients | Clients > Access Type |
| Clients | Exact redirect URIs, no wildcards | Clients > Valid Redirect URIs |
| Clients | PKCE for public clients | Clients > Advanced |
| Clients | Restrict offline_access scope | Clients > Client Scopes |
| Auditing | Enable login and admin events | Realm Settings > Events |
| Auditing | Forward to SIEM | Custom EventListenerProvider |
| Auditing | Alert on anomalous patterns | SIEM rules |
| Platform | Keep Keycloak current | Patch process |
| Platform | DB user least privilege | Database config |
| Platform | Secrets in secrets manager | Infrastructure |
| Platform | Disable unneeded features | Realm Settings |
Frequently asked questions
Is Keycloak secure by default?
Keycloak’s defaults are designed to minimize friction for developers, not to harden production deployments. Brute-force protection is disabled, redirect URIs accept wildcards, and admin console access is unrestricted by network. These are reasonable development-environment trade-offs, the problem arises when they survive into production unchanged.
How do I harden the Keycloak admin console?
The two highest-impact controls are network isolation and MFA. Ensure the /admin path and Admin REST API are reachable only from an internal network segment or a dedicated listener port protected by a firewall rule. Require a second factor for every account holding any admin role, including realm-admin in non-master realms. Adding a strong password policy and audit logging covers the rest of the admin console attack surface.
What are the most important Keycloak security settings?
If you can only address a short list, prioritize these five: enable brute-force detection (Realm Settings > Security Defenses), disable Full Scope Allowed on every client, set exact redirect URIs, enable refresh-token rotation (Revoke Refresh Token), and ensure all admin accounts use MFA. These five settings address the most commonly exploited misconfigurations in Keycloak deployments.
How often should I rotate Keycloak client secrets?
Rotate confidential client secrets every 90 days at minimum, and immediately after any suspected compromise or relevant personnel change. Regenerate secrets in the admin console under Clients > Credentials > Regenerate. High-privilege service accounts with Admin API access should be rotated monthly. Build rotation into your operations runbook from the start, retrofitting it later is significantly harder.
Should I use Keycloak’s built-in brute-force protection or a WAF?
Both, because they defend against different threat models. Keycloak’s built-in protection (Realm Settings > Security Defenses > Brute Force Detection) tracks failures per username and enforces account lockouts. A WAF or proxy-level rate limiter tracks failures per IP and blocks distributed attacks that spread attempts across many usernames, staying below per-account thresholds. The two controls are complementary: Keycloak handles per-account lockout, the WAF handles volumetric and distributed attacks.
Next steps
Working through this checklist moves your Keycloak deployment from development-friendly defaults to a defensible production posture. If you want the hardened baseline maintained without the operational overhead, Skycloak provides managed Keycloak hosting with patch management and built-in audit log forwarding included.
Further reading:
- Keycloak production-ready checklist, broader production readiness beyond security
- Securing your Keycloak master realm, master-realm hardening deep dive
- Keycloak auditing and event logging complete guide, full event logging reference
- Keycloak brute-force IP-based protection gap, distributed attack mitigation
- Keycloak refresh token rotation guide, token rotation implementation
Ready to simplify your authentication?
Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.