Password policies in Keycloak are more than just a checkbox; they’re the gatekeepers of your user base’s security, and understanding their nuances can prevent a surprising amount of credential-related headaches. The most counterintuitive thing about Keycloak’s password policies is that they don’t enforce all complexity rules at the database level; they primarily act as client-side and early server-side validation, meaning a determined attacker might bypass some checks if they can directly manipulate the password reset or creation flow at a lower level.
Let’s see this in action. Imagine we have a Keycloak realm named myrealm and we want to enforce a policy that requires passwords to be at least 8 characters long, contain at least one digit, and at least one uppercase letter.
First, we navigate to the Keycloak Admin Console. For myrealm, we go to Realm Settings -> Login.
Here, you’ll find the Password Policy section. We can add policy requirements.
require-digits=on
require-uppercase=on
minLength=8
When a user attempts to set or reset their password through Keycloak’s standard flows (like the account console or the login page’s "Forgot Password" flow), these rules are checked.
Consider a user trying to set their password to password. Keycloak’s UI will immediately flag this as invalid, showing an error like: "Password must contain at least one digit and one uppercase letter."
If they try pass123, it will complain about the uppercase letter. If they try Pass123, it will complain about the length. Only when they enter something like Pass123! (assuming we also had require-special-characters=on) would it pass these specific checks.
The underlying mechanism involves Keycloak’s PasswordPolicyManager. When a password change request comes in, Keycloak iterates through the configured policy requirements. For each requirement (e.g., require-digits), it applies a specific checker. If any checker fails, an error is returned, and the password change is rejected.
The require-digits=on policy uses a regular expression like .*\\d.* to ensure at least one digit is present. require-uppercase=on uses .*[A-Z].*. minLength=8 is a straightforward length check.
Beyond these, Keycloak offers several other useful policies:
require-lowercase=on: Ensures at least one lowercase letter. Uses.*[a-z].*.require-special-characters=on: Ensures at least one special character (defined inspcial-charsproperty, defaults to!@#$%^&*()_+=-[]{}|~). Uses.*[!@#$%^&*()_+=\\[\\]{}|~-].*.exclude-username=on: Prevents the password from being the same as the username.max-age=365: Forces a password change every 365 days.history=5: Prevents the user from reusing the last 5 passwords.
The history policy is particularly interesting. When a user changes their password, Keycloak stores a hash of the new password along with a timestamp. Before accepting a new password, it checks if the hash of the proposed new password matches any of the stored hashes for that user within the history window. This prevents users from simply cycling through a few weak passwords.
The one thing most people don’t realize is how Keycloak handles credential validation during direct API calls or when integrating with custom authentication flows. If you’re bypassing Keycloak’s built-in forms and directly invoking the UserStorageProvider or CredentialInput interfaces, you might inadvertently bypass some of these client-side or initial server-side checks. The PasswordPolicyManager is still accessible, but you need to explicitly call its validatePassword method with the user and the new password to ensure all configured policies are applied. Failing to do so means the complexity rules you painstakingly configured might not be enforced for all password change scenarios.
After successfully enforcing your password complexity rules, the next logical step is to consider how users manage their accounts, leading you to explore Keycloak’s Account Management services and their configuration.