<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Password - Inero Software - Software Consulting</title>
	<atom:link href="https://inero-software.com/tag/password/feed/" rel="self" type="application/rss+xml" />
	<link>https://inero-software.com/tag/password/</link>
	<description>We unleash innovations using cutting-edge technologies, modern design and AI</description>
	<lastBuildDate>Tue, 01 Apr 2025 09:31:39 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://inero-software.com/wp-content/uploads/2018/11/inero-logo-favicon.png</url>
	<title>Password - Inero Software - Software Consulting</title>
	<link>https://inero-software.com/tag/password/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">153509928</site>	<item>
		<title>Configuring Password Policies in Keycloak</title>
		<link>https://inero-software.com/configuring-password-policies-in-keycloak/</link>
		
		<dc:creator><![CDATA[Marceli Formela]]></dc:creator>
		<pubDate>Thu, 20 Mar 2025 12:10:07 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Company]]></category>
		<category><![CDATA[Keycloak]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[keycloak]]></category>
		<category><![CDATA[Password]]></category>
		<category><![CDATA[password management]]></category>
		<category><![CDATA[password policies]]></category>
		<guid isPermaLink="false">https://inero-software.com/?p=7635</guid>

					<description><![CDATA[<p>In this blog, we will first take a look at the built-in Keycloak mechanisms for password policy management. Then, we will explore the possibilities for customizing these mechanisms to better fit specific requirements.</p>
<p>Artykuł <a href="https://inero-software.com/configuring-password-policies-in-keycloak/">Configuring Password Policies in Keycloak</a> pochodzi z serwisu <a href="https://inero-software.com">Inero Software - Software Consulting</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="7635" class="elementor elementor-7635" data-elementor-post-type="post">
				<div class="elementor-element elementor-element-949c242 e-flex e-con-boxed e-con e-parent" data-id="949c242" data-element_type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-a9078db elementor-widget elementor-widget-html" data-id="a9078db" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			 
		</div>
				</div>
				<div class="elementor-element elementor-element-cc34f5b elementor-widget elementor-widget-text-editor" data-id="cc34f5b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<h4><strong>Effective password management is an important aspect of securing user accounts, and Keycloak provides tools to enforce strong authentication policies. By configuring password rules, administrators can ensure that credentials meet security standards, reducing the risk of unauthorized access. The framework offers flexible options, allowing you to set requirements for password length, complexity, expiration, and reuse prevention. </strong></h4>						</div>
				</div>
				<div class="elementor-element elementor-element-0df981b elementor-widget elementor-widget-text-editor" data-id="0df981b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">In this blog, we will first take a look at the built-in Keycloak mechanisms for password policy management. Then, we will explore the possibilities for customizing these mechanisms to better fit specific requirements.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-ad5f7b2 elementor-widget elementor-widget-image" data-id="ad5f7b2" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img fetchpriority="high" decoding="async" data-attachment-id="7638" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/115856/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/115856.png" data-orig-size="775,411" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="115856" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/115856-300x159.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/115856.png" tabindex="0" role="button" width="775" height="411" src="https://inero-software.com/wp-content/uploads/2025/03/115856.png" class="attachment-large size-large wp-image-7638" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/03/115856.png 775w, https://inero-software.com/wp-content/uploads/2025/03/115856-300x159.png 300w, https://inero-software.com/wp-content/uploads/2025/03/115856-768x407.png 768w, https://inero-software.com/wp-content/uploads/2025/03/115856-566x300.png 566w" sizes="(max-width: 775px) 100vw, 775px" data-attachment-id="7638" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/115856/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/115856.png" data-orig-size="775,411" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="115856" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/115856-300x159.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/115856.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-b583771 elementor-widget elementor-widget-heading" data-id="b583771" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Built-in policies</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-b2a2079 elementor-widget elementor-widget-text-editor" data-id="b2a2079" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">These built-in password policies in Keycloak allow administrators to enforce security rules to strengthen user authentication. Here’s a brief description of each policy:</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-1dcf64f elementor-widget elementor-widget-text-editor" data-id="1dcf64f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ol><li aria-level="1"><strong>Expire Password</strong> <span style="font-weight: 400;">– Forces users to change their password after a specified period.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Hashing Iterations</strong> – Determines the number of iterations for password hashing to enhance security.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Not Recently Used</strong> – Prevents users from reusing their recent passwords.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Password Blacklist</strong> – Blocks specific passwords from being used, typically to prevent weak or common passwords.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Regular Expression</strong> – Allows enforcing a custom regex pattern for password validation.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Minimum Length</strong> – Sets the minimum number of characters required in a password.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Not Username</strong> – Prevents users from setting their username as a password.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Not Email</strong> – Prevents users from using their email address as a password.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Not Recently Used</strong> (In Days) – Prevents password reuse within a specified number of days.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Not Contains Username</strong> – Ensures the password does not include the username as part of it.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Special Character</strong>s – Requires passwords to contain at least one special character.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Uppercase Characters</strong> – Enforces at least one uppercase letter in the password.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Lowercase Characters</strong> – Requires at least one lowercase letter in the password.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Digits</strong> – Ensures the password includes at least one numeric digit.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Maximum Authentication Age</strong> – Sets a limit on how long authentication remains valid before requiring reauthentication.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Hashing Algorithm</strong> – Specifies the hashing algorithm used for password encryption.</span></li><li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><strong>Maximum Length</strong> – Defines the maximum allowable length for passwords.</span></li></ol>						</div>
				</div>
				<div class="elementor-element elementor-element-95da107 elementor-widget elementor-widget-heading" data-id="95da107" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Implementing custom policy using SPI</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-86f9385 elementor-widget elementor-widget-text-editor" data-id="86f9385" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">To implement a custom password policy in Keycloak, we should use the Service Provider Interface (SPI).</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-efcfbc7 elementor-widget elementor-widget-text-editor" data-id="efcfbc7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">In this case, we define a custom password policy provider by implementing the PasswordPolicyProviderFactory interface:</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-a47d185 elementor-widget elementor-widget-code-highlight" data-id="a47d185" data-element_type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
					<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>public class PasswordCustomPolicyProviderFactory implements PasswordPolicyProviderFactory {

	public static final Integer DEFAULT_VALUE = 1;
	public static final String MIN_PASSWORD_LIFETIME_ID = "minimumPasswordLifetime";

	@Override
	public String getId() {
    	return MIN_PASSWORD_LIFETIME_ID;
	}

	@Override
	public PasswordPolicyProvider create(KeycloakSession session) {
    	return new PasswordCustomPolicyProvider(session);
	}
[...]
}

</xmp>
				</code>
			</pre>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-75140a5 elementor-widget elementor-widget-text-editor" data-id="75140a5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Factory instantiates and returns a new instance of <strong>PasswordCustomPolicyProvider</strong>, which contains the actual validation logic for enforcing the minimum password lifetime. The <strong>MIN_PASSWORD_LIFETIME_ID</strong> constant serves as the unique identifier for this custom policy </span><span style="font-weight: 400;">and <strong>DEFAULT_VALUE</strong> constant represents the default minimum password lifetime (in days) if no custom value is configured via admin console.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-3c1cd5b elementor-widget elementor-widget-code-highlight" data-id="3c1cd5b" data-element_type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
					<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>public class PasswordCustomPolicyProvider implements PasswordPolicyProvider {
np.
   private static final String POLICY_VIOLATION_MESSAGE = "passwordLifetimeViolation";


   private final KeycloakSession keycloakSession;

   public PasswordCustomPolicyProvider(KeycloakSession keycloakSession) {
   	this.keycloakSession = keycloakSession;
   }


   @Override
   public PolicyError validate(RealmModel realm, UserModel user, String password) {
   	PasswordCredentialProvider credentialProvider = new PasswordCredentialProvider(keycloakSession);
   	PasswordCredentialModel credentialModel = credentialProvider.getPassword(realm, user);

   	if (credentialModel == null) {
       	return null;
   	}

   	long passwordCreationTime = credentialModel.getCreatedDate();
   	long currentTime = Time.currentTimeMillis();
   	long elapsedTime = currentTime - passwordCreationTime;

   	PasswordPolicy passwordPolicy = realm.getPasswordPolicy();
   	int minPasswordLifetimeDays = passwordPolicy.getPolicyConfig(PasswordCustomPolicyProviderFactory.MIN_PASSWORD_LIFETIME_ID);
   	long minPasswordLifetimeMillis = TimeUnit.DAYS.toMillis(minPasswordLifetimeDays);
   	return elapsedTime >= minPasswordLifetimeMillis ? null : new PolicyError(POLICY_VIOLATION_MESSAGE, minPasswordLifetimeDays);
   }
[...]
}
</xmp>
				</code>
			</pre>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-7cd9848 elementor-widget elementor-widget-text-editor" data-id="7cd9848" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">The <strong>PasswordCredentialProvider</strong> can access the stored password creation timestamp via the <strong>PasswordCredentialModel</strong> instance. It then computes <strong>elapsedTime</strong> as the difference between this timestamp and the current system time, representing how long the password has been in use.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-c8ec00f elementor-widget elementor-widget-text-editor" data-id="c8ec00f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Next, the PasswordPolicy object retrieves the password policy for the realm, extracts the minimum required password lifetime in days (minPasswordLifetimeDays), and converts it to milliseconds (minPasswordLifetimeMillis). The policy ensures that the password has been in use for at least the required duration. If this requirement is not met, a PolicyError is returned. The error message key is stored in <strong>POLICY_VIOLATION_MESSAGE</strong>, and its content can be customized within our theme. This allows us to define a user-friendly message that informs the user why the password change is restricted and how much time remains before a new password can be set.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-5c8b84b elementor-widget elementor-widget-image" data-id="5c8b84b" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img decoding="async" data-attachment-id="7639" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/122254/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/122254.png" data-orig-size="711,443" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="122254" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/122254-300x187.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/122254.png" tabindex="0" role="button" width="711" height="443" src="https://inero-software.com/wp-content/uploads/2025/03/122254.png" class="attachment-large size-large wp-image-7639" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/03/122254.png 711w, https://inero-software.com/wp-content/uploads/2025/03/122254-300x187.png 300w, https://inero-software.com/wp-content/uploads/2025/03/122254-481x300.png 481w" sizes="(max-width: 711px) 100vw, 711px" data-attachment-id="7639" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/122254/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/122254.png" data-orig-size="711,443" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="122254" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/122254-300x187.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/122254.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-a18d447 elementor-widget elementor-widget-text-editor" data-id="a18d447" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">In this way, we can define custom password policies in Keycloak when the default set of policies is insufficient for specific requirements. This flexibility allows for more granular control over user authentication and password management when we need it.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-ed723ca elementor-widget elementor-widget-heading" data-id="ed723ca" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Customizing UI to improve user experience</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-0d876c8 elementor-widget elementor-widget-text-editor" data-id="0d876c8" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">By default, Keycloak displays unsatisfied password policies</span><b> individually </b><span style="font-weight: 400;">on the login page. This can be problematic for many users, especially when there are multiple policies that are not met. It can lead to a cluttered interface and make it harder for users to understand all the password requirements at once. To address this, you can customize the login screen to display a collective list of all unsatisfied password policies together, providing a clearer and more user-friendly experience.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-129921c elementor-widget elementor-widget-code-highlight" data-id="129921c" data-element_type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
					<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>public class CustomFreeMarkerLoginFormsProvider extends FreeMarkerLoginFormsProvider {
/**
* Mapping between password policy provider IDs and custom messages
* Note: contains only standard policies that must be displayed in the UI
*/
private final Map<String, String> policyPropertyMessages = Map.of(
LengthPasswordPolicyProviderFactory.ID, MINIMUM_LENGTH_MESSAGE,
MaximumLengthPasswordPolicyProviderFactory.ID, MAXIMUM_LENGTH_MESSAGE,
DigitsPasswordPolicyProviderFactory.ID, MINIMUM_DIGIT_MESSAGE,
SpecialCharsPasswordPolicyProviderFactory.ID, MINIMUM_SPECIAL_CHAR_MESSAGE,
UpperCasePasswordPolicyProviderFactory.ID, MINIMUM_UPPERCASE_MESSAGE,
LowerCasePasswordPolicyProviderFactory.ID, MINIMUM_LOWERCASE_MESSAGE,
NotUsernamePasswordPolicyProviderFactory.ID, NOT_USERNAME_MESSAGE,
NotContainsUsernamePasswordPolicyProviderFactory.ID, NOT_CONTAINS_USERNAME_MESSAGE,
NotEmailPasswordPolicyProviderFactory.ID, NOT_EMAIL_MESSAGE
);

[...]

@Override
protected void createCommonAttributes(Theme theme, Locale locale, Properties messagesBundle,
UriBuilder baseUriBuilder, LoginFormsPages page) {
super.createCommonAttributes(theme, locale, messagesBundle, baseUriBuilder, page);
if (realm != null && realm.getPasswordPolicy() != null) {
attributes.put("passwordPolicies", getPasswordPolicyMessages(realm.getPasswordPolicy(), messagesBundle));
}}

[...]

private Map<String, String> getPasswordPolicyMessages(PasswordPolicy passwordPolicy, Properties messagesBundle) {
Map<String, String> policyMessages = new HashMap<>();
PasswordPolicy.Builder builder = passwordPolicy.toBuilder();
for (String policyName : passwordPolicy.getPolicies()) {
var value = builder.get(policyName);
String message = extractPolicyMessage(policyName, value, messagesBundle);
if (message != null) {
policyMessages.put(policyName, message);
}
}
return policyMessages;
}

[...]

/**
* Extracts a message for a given password policy from the messages bundle
* Note: Policy message is constructed by replacing the {0} placeholder with the policy value
*/
private String extractPolicyMessage(String policy, String value, Properties messagesBundle) {
String property = policyPropertyMessages.get(policy);
if (property == null) {
return null;
}
String policyMessage = messagesBundle.getProperty(property);
return policyMessage != null ? policyMessage.replace("{0}", value) : null;
}
</xmp>
				</code>
			</pre>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-e47c0c6 elementor-widget elementor-widget-text-editor" data-id="e47c0c6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">The getPasswordPolicyMessages() function already collects the password policies from the PasswordPolicy and maps them to the appropriate messages from the message bundle. You can extend this function to display all unsatisfied policies in one collective message.</span></p><p> </p><p><span style="font-weight: 400;">Password policies such as minimum length, required digits, special characters, etc., are mapped to messages via the extractPolicyMessage() method. Our service implementation will iterate through each policy and check if it&#8217;s satisfied. If not, the corresponding message will be displayed.</span></p><p> </p><p><span style="font-weight: 400;">In your update-password.ftl page, you can display these unsatisfied policies as a list using FreeMarker.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-e70d98c elementor-widget elementor-widget-code-highlight" data-id="e70d98c" data-element_type="widget" data-widget_type="code-highlight.default">
				<div class="elementor-widget-container">
					<div class="prismjs-default copy-to-clipboard ">
			<pre data-line="" class="highlight-height language-javascript line-numbers">
				<code readonly="true" class="language-javascript">
					<xmp>
    	<#if passwordPolicies?has_content>
        	<div class="${properties.kcAlertClass}">
            	<div class="${properties.kcAlertIconWrapperClass}">
                	<span class="${properties.kcAlertIconClass}"></span>
            	</div>
            	<span class="${properties.kcAlertTitleClass}">
            	${msg("passwordInstruction")} <br>
            	<#list passwordPolicies?keys as key>
                	<span class="${properties.kcAlertTitleClass}">&#x2022; ${passwordPolicies[key]}</span><br/>
            	</#list>
            	</span>
        	</div>
    	</#if>

</xmp>
				</code>
			</pre>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-358fd5c elementor-widget elementor-widget-image" data-id="358fd5c" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img decoding="async" data-attachment-id="7640" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/123206/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/123206.png" data-orig-size="648,510" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="123206" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/123206-300x236.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/123206.png" tabindex="0" role="button" width="648" height="510" src="https://inero-software.com/wp-content/uploads/2025/03/123206.png" class="attachment-large size-large wp-image-7640" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/03/123206.png 648w, https://inero-software.com/wp-content/uploads/2025/03/123206-300x236.png 300w, https://inero-software.com/wp-content/uploads/2025/03/123206-381x300.png 381w, https://inero-software.com/wp-content/uploads/2025/03/123206-380x300.png 380w" sizes="(max-width: 648px) 100vw, 648px" data-attachment-id="7640" data-permalink="https://inero-software.com/configuring-password-policies-in-keycloak/attachment/123206/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/03/123206.png" data-orig-size="648,510" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="123206" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/03/123206-300x236.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/03/123206.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-6d7a6c0 elementor-widget elementor-widget-heading" data-id="6d7a6c0" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Real world policy examples
</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-776740f elementor-widget elementor-widget-text-editor" data-id="776740f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Let&#8217;s see how password policies look in large companies.</span></p><p><span style="font-weight: 400;"> </span></p><p><b>Apple</b><span style="font-weight: 400;"> requires passwords to be at least eight characters long and must include both letters and numbers. Additionally, passwords cannot contain three or more consecutive identical characters and cannot be commonly used passwords.</span></p><p><span style="font-weight: 400;"> </span></p><p><b>Facebook</b><span style="font-weight: 400;"> enforces a minimum password length of more than six characters, although longer passwords are recommended. While Meta does not require the use of special characters or digits, it encourages creating complex passwords.</span></p><p><span style="font-weight: 400;"> </span></p><p><b>Microsoft</b><span style="font-weight: 400;"> passwords must be at least 8 characters long and contain at least two of the following types of characters: uppercase letters, lowercase letters, digits, and symbols. Additionally, it may block the ability to set a password that is too similar to the previous one.</span></p><p><span style="font-weight: 400;">Although these companies use different tools for authentication, it&#8217;s important to consider the security standards implemented in big real-world systems.</span></p><p><span style="font-weight: 400;"> </span></p><p><span style="font-weight: 400;">And despite the fact that these password policies are not extremely restrictive, users should still avoid using sensitive personal information, such as names, birthdates, or phone numbers, in their passwords. Additionally, it&#8217;s essential to avoid reusing passwords across different services, as this can lead to vulnerabilities in case one account is compromised. Employing two-factor authentication (2FA) and periodically reviewing password security are further steps users can take to enhance their protection.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-d64b6d9 elementor-widget elementor-widget-heading" data-id="d64b6d9" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Summary</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-911c3a6 elementor-widget elementor-widget-text-editor" data-id="911c3a6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">As you can see now, Keycloak provides a set of default password policies that cover standard security rules, such as minimum length, complexity requirements, and password history. These built-in policies are sufficient in many cases, but if needed, there is the option to customize them to meet specific organizational requirements. Keycloak also allows the creation of custom password policies, providing greater control over security.</span></p><p><span style="font-weight: 400;">In addition to customizing policies, Keycloak enables modification of the user interface, which is especially useful when the default display of password policy violations, such as showing unmet requirements individually, does not meet our needs. In such cases, we can change how errors are presented or enrich the messages with additional details to make them more user-friendly.</span></p><p> </p><p><span style="font-weight: 400;">With these options, Keycloak demonstrates a high level of flexibility, allowing full control over security policies and the user interface, making it a versatile solution for identity and access management. The ability to define custom rules and adjust components ensures that Keycloak is a scalable tool that can be easily tailored to the specific needs of an organization.</span></p>						</div>
				</div>
					</div>
				</div>
				</div>
		<p>Artykuł <a href="https://inero-software.com/configuring-password-policies-in-keycloak/">Configuring Password Policies in Keycloak</a> pochodzi z serwisu <a href="https://inero-software.com">Inero Software - Software Consulting</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">7635</post-id>	</item>
	</channel>
</rss>
