
[[_password-policies]]

=== Password policies

When {project_name} creates a realm, it does not associate password policies with the realm. You can set a simple password with no restrictions on its length, security, or complexity. Simple passwords are unacceptable in production environments. {project_name} has a set of password policies available through the Admin Console.

.Procedure
. Click *Authentication* in the menu.
. Click the *Policies* tab.
. Select the policy to add in the *Add policy* drop-down box.
. Enter a value that applies to the policy chosen.
. Click *Save*.
+
.Password policy
image:images/password-policy.png[Password Policy]

After saving the policy, {project_name} enforces the policy for new users.

[NOTE]
====
The new policy will not be effective for existing users. Therefore, make sure that you set the password policy from the beginning of the realm creation or add "Update password" to existing users  or use "Expire password" to make sure that users update their passwords in next "N" days, which will actually adjust to new password policies.
====

==== Password policy types

===== HashAlgorithm

Passwords are not stored in cleartext. Before storage or validation, {project_name} hashes passwords using standard hashing algorithms.

Supported password hashing algorithms are shown in the following table.

[%autowidth,cols="m,"]
|===
|Hashing algorithm |Description

| argon2
| Argon2 (default for non-FIPS deployments)

| pbkdf2-sha512
| PBKDF2 with SHA512 (default for FIPS deployments)

| pbkdf2-sha256
| PBKDF2 with SHA256

| pbkdf2
| PBKDF2 with SHA1 (deprecated)

|===

It is highly recommended to use Argon2 when possible as it has significantly less CPU requirements compared to PBKDF2, while
at the same time being more secure.

The default password hashing algorithm for the server can be configured with `+--spi-password-hashing--provider-default=<algorithm>+`.

To prevent excessive memory and CPU usage, the parallel computation of hashes by Argon2 is by default limited to the number of cores available to the JVM.
To configure the Argon2 hashing provider, use its provider options.

See the link:{developerguide_link}[{developerguide_name}] on how to add your own hashing algorithm.

[NOTE]
====
If you change the hashing algorithm, password hashes in storage will not change until the user logs in.
====

===== Hashing iterations
Specifies the number of times {project_name} hashes passwords before storage or verification. The default value is -1,
which uses the default hashing iterations for the selected hashing algorithm as listed in the following table.

[%autowidth,cols="m,>"]
|===
|Hashing algorithm |Default hash iterations

| argon2
| 5

| pbkdf2-sha512
| 210,000

| pbkdf2-sha256
| 600,000

| pbkdf2
| 1,300,000

|===

[NOTE]
====
In most cases the hashing iterations should not be changed from the recommended default values. Lower values for
iterations provide insufficient security, while higher values result in higher CPU power requirements.
====

===== Digits

The number of numerical digits required in the password string.

===== Lowercase characters

The number of lower case letters required in the password string.

===== Uppercase characters

The number of upper case letters required in the password string.

===== Special characters

The number of special characters required in the password string.

===== Not username

The password cannot be the same as the username.

===== Not email

The password cannot be the same as the email address of the user.

===== Regular expression

Password must match one or more defined Java regular expression patterns.
See https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Pattern.html[Java's regular expression documentation] for the syntax of those expressions.

===== Expire password

The number of days the password is valid. When the number of days has expired, the user must change their password.

===== Not recently used

Password cannot be already used by the user. {project_name} stores a history of used passwords. The number of old passwords stored is configurable in {project_name}.

===== Not recently used (In Days)

Password cannot be reused within the configured time period (in days).
If the new password was last set within this period, the user will be forced to provide a different one.

===== Password blacklist
Password must not be in a blacklist file.

* Blacklist files are UTF-8 plain-text files with Unix line endings. Every line represents a blacklisted password.
* {project_name} compares passwords in a case-insensitive manner.
* The value of the blacklist file must be the name of the blacklist file, for example, `100k_passwords.txt`.
* Blacklist files resolve against `+${kc.home.dir}/data/password-blacklists/+` by default. Customize this path using:
** The `keycloak.password.blacklists.path` system property.
** The `blacklistsPath` property of the `passwordBlacklist` policy SPI configuration. To configure the blacklist folder using the CLI, use `+--spi-password-policy--password-blacklist--blacklists-path=/path/to/blacklistsFolder+`.

.A note about False Positives

The current implementation uses a BloomFilter for fast and memory efficient containment checks, such as whether a given password is contained in a blacklist, with the possibility for false positives.

* By default a false positive probability of `0.01%` is used.
* To change the false positive probability by CLI configuration, use `+--spi-password-policy--password-blacklist--false-positive-probability=0.00001+`.

[[maximum-authentication-age]]
===== Maximum Authentication Age

Specifies the maximum age of a user authentication in seconds with which the user can update a password without re-authentication. A value of `0` indicates that the user has to always re-authenticate with their current password before they can update the password.
See <<con-aia-reauth_{context}, AIA section>> for some additional details about this policy.

NOTE: The Maximum Authentication Age is configurable also when configuring the required action *Update Password* in the *Required Actions* tab in the Admin Console. The better choice is to use  the
required action for the configuration because the _Maximum Authentication Age_ password policy might be deprecated/removed in the future.
