<?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>2FA - Inero Software - Software Consulting</title>
	<atom:link href="https://inero-software.com/tag/2fa/feed/" rel="self" type="application/rss+xml" />
	<link>https://inero-software.com/tag/2fa/</link>
	<description>We unleash innovations using cutting-edge technologies, modern design and AI</description>
	<lastBuildDate>Thu, 06 Mar 2025 10:53:55 +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>2FA - Inero Software - Software Consulting</title>
	<link>https://inero-software.com/tag/2fa/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">153509928</site>	<item>
		<title>Trusted devices in Keycloak</title>
		<link>https://inero-software.com/trusted-devices-in-keycloak/</link>
		
		<dc:creator><![CDATA[Marta Kuprasz]]></dc:creator>
		<pubDate>Thu, 06 Mar 2025 10:47:08 +0000</pubDate>
				<category><![CDATA[Company]]></category>
		<category><![CDATA[Keycloak]]></category>
		<category><![CDATA[2FA]]></category>
		<category><![CDATA[corporate]]></category>
		<category><![CDATA[cybersecurity]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[keycloak]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[trusted devices]]></category>
		<guid isPermaLink="false">https://inero-software.com/?p=7522</guid>

					<description><![CDATA[<p>The trusted devices mechanism in Keycloak is a way to enhance login convenience without significantly compromising cybersecurity.</p>
<p>Artykuł <a href="https://inero-software.com/trusted-devices-in-keycloak/">Trusted devices 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="7522" class="elementor elementor-7522" data-elementor-post-type="post">
				<div class="elementor-element elementor-element-61f5765 e-flex e-con-boxed e-con e-parent" data-id="61f5765" data-element_type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-bd55449 elementor-widget elementor-widget-html" data-id="bd55449" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			 		</div>
				</div>
				<div class="elementor-element elementor-element-a676703 elementor-widget elementor-widget-text-editor" data-id="a676703" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<h4>User authentication in IT systems requires finding a balance between convenience and security. On one hand, users expect the login process to involve the fewest steps possible; on the other, it is essential to protect system access from unauthorized use. One way to manage security levels flexibly is through the trusted devices mechanism, which allows users to reduce the number of required login steps for recognized and secure devices.</h4>						</div>
				</div>
				<div class="elementor-element elementor-element-56ff357 elementor-widget elementor-widget-text-editor" data-id="56ff357" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>The stricter the security policy, the more inconvenient it becomes for users—this is the eternal dilemma for system administrators. Long and complex passwords, frequent password changes, and additional authentication factors enhance security but also lead users to find ways to bypass procedures—such as writing passwords down in notebooks or saving them in browsers.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-2bce090 elementor-widget elementor-widget-heading" data-id="2bce090" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Trusted Devices – How Does It Work?</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-50fe905 elementor-widget elementor-widget-text-editor" data-id="50fe905" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>By default, Keycloak does not recognize or remember devices, meaning each session is treated independently. However, with extensions, support for trusted devices can be added, allowing users to skip certain steps during subsequent logins.</p><p><span data-ccp-props="{}"> </span></p><p>CTO of Inero Software, Waldemar Korłub, emphasizes:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-696e202 elementor-blockquote--skin-border elementor-blockquote--button-color-official elementor-widget elementor-widget-blockquote" data-id="696e202" data-element_type="widget" data-widget_type="blockquote.default">
				<div class="elementor-widget-container">
					<blockquote class="elementor-blockquote">
			<p class="elementor-blockquote__content">
				"Hence the concept of trusted devices – the first time, we need to go through all the steps, but afterward, the application can, for example, skip asking for the two-factor authentication code."			</p>
					</blockquote>
				</div>
				</div>
				<div class="elementor-element elementor-element-f14d2c6 elementor-widget elementor-widget-text-editor" data-id="f14d2c6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Once a device is marked as &#8220;trusted,&#8221; the system can retain its status for a specified period, allowing for a simplified login process. However, the user may still be periodically asked to reauthenticate to ensure security.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b8b437d elementor-widget elementor-widget-heading" data-id="b8b437d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Is remembering devices secure?</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-785c726 elementor-widget elementor-widget-text-editor" data-id="785c726" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>While the trusted devices mechanism improves user convenience, it also introduces additional risks. The biggest threat is the theft or loss of a device that has been previously marked as trusted.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-a64bc8c elementor-widget elementor-widget-text-editor" data-id="a64bc8c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>As Waldemar Korłub points out:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-d11c9c8 elementor-blockquote--skin-border elementor-blockquote--button-color-official elementor-widget elementor-widget-blockquote" data-id="d11c9c8" data-element_type="widget" data-widget_type="blockquote.default">
				<div class="elementor-widget-container">
					<blockquote class="elementor-blockquote">
			<p class="elementor-blockquote__content">
				"If the system does not require an additional authentication factor, an attacker could gain access to all stored applications. That’s why it is crucial for users to have control over their trusted devices—ideally through a panel where they can remove them at any time."			</p>
					</blockquote>
				</div>
				</div>
					</div>
				</div>
		<div class="elementor-element elementor-element-1059003 e-flex e-con-boxed e-con e-parent" data-id="1059003" data-element_type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-aa6f62d elementor-widget elementor-widget-text-editor" data-id="aa6f62d" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Introducing a device management panel and the option to revoke a device&#8217;s trusted status in case of loss are essential elements for ensuring security.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-0483644 elementor-widget elementor-widget-heading" data-id="0483644" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">How can administrators control access in Keycloak?</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-84cbf21 elementor-widget elementor-widget-text-editor" data-id="84cbf21" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Administrators can restrict the device remembering mechanism, for example, to specific networks or corporate devices.</p><p>Waldemar Korłub explains:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-4323398 elementor-blockquote--skin-border elementor-blockquote--button-color-official elementor-widget elementor-widget-blockquote" data-id="4323398" data-element_type="widget" data-widget_type="blockquote.default">
				<div class="elementor-widget-container">
					<blockquote class="elementor-blockquote">
			<p class="elementor-blockquote__content">
				"We can limit this mechanism, for example, to computers within the local network—if users connect via the corporate VPN, we can recognize company-owned devices and enable the trusted devices option for them."			</p>
					</blockquote>
				</div>
				</div>
				<div class="elementor-element elementor-element-4265831 elementor-widget elementor-widget-text-editor" data-id="4265831" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Thanks to such solutions, organizations can prevent users from assigning trusted status to personal devices that are beyond their control.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-32fce0a elementor-widget elementor-widget-heading" data-id="32fce0a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Trusted Devices in Keycloak – Key Takeaways</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-d135dd4 elementor-widget elementor-widget-text-editor" data-id="d135dd4" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li data-leveltext="" data-font="Symbol" data-listid="13" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559683&quot;:0,&quot;335559684&quot;:-2,&quot;335559685&quot;:717,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><p><strong>Trusted Devices Help Simplify Login but Require Proper Security Measures</strong></p><p>The trusted devices mechanism in Keycloak allows users to skip certain authentication steps, such as entering a 2FA code. While this is a convenient solution that streamlines daily operations, it also requires the implementation of appropriate security measures. It is essential to define the validity period of a trusted device and monitor changes in login behavior to prevent misuse.</p></li></ul></li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-e312c00 elementor-widget elementor-widget-text-editor" data-id="e312c00" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li data-leveltext="" data-font="Symbol" data-listid="14" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559683&quot;:0,&quot;335559684&quot;:-2,&quot;335559685&quot;:717,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><p><strong>Administrators Can Control the Trusted Device Access Policy</strong></p><p>Not every device should be marked as trusted, which is why administrators can restrict this feature to corporate computers or require a VPN connection. This helps prevent situations where a user assigns trusted status to a personal computer that the organization cannot control.</p></li></ul></li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-715f0c8 elementor-widget elementor-widget-text-editor" data-id="715f0c8" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li><p><strong>Device Management Panel Enhances Security</strong></p><p>To give users greater control over their sessions, it is beneficial to implement a panel that allows them to review and remove trusted devices. This way, in case of device loss or suspected unauthorized access, users can quickly revoke granted permissions.</p></li></ul></li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-1e4653d elementor-widget elementor-widget-text-editor" data-id="1e4653d" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li data-leveltext="" data-font="Symbol" data-listid="16" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559683&quot;:0,&quot;335559684&quot;:-2,&quot;335559685&quot;:717,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><p><strong>The Ability to Remove a Device Protects Against Account Takeover</strong></p><p>If a device is lost or stolen and the system does not require additional authentication, an attacker could gain access to the user&#8217;s account. That’s why it is crucial to allow the removal of trusted devices at any time and enforce reauthentication. This approach provides greater flexibility while reducing the risk of unauthorized account access.</p></li></ul></li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-74208e6 elementor-widget elementor-widget-heading" data-id="74208e6" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">When Should You Use the Trusted Devices Feature in Keycloak?</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c9a0c94 elementor-widget elementor-widget-text-editor" data-id="c9a0c94" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>The trusted devices feature in Keycloak enhances login convenience while maintaining a high level of security. This functionality is particularly useful in corporate environments and BYOD (Bring Your Own Device) models, where users regularly log in from the same devices.</p><p>Marking a device as trusted reduces the number of two-factor authentication (2FA) prompts, extends session duration, and allows for dynamic security policy adjustments, such as requiring reauthentication for suspicious logins. This approach helps mitigate the risk of account takeover—even if an attacker obtains a password and 2FA code—since logging in from a new device may trigger additional verification.</p><p>Implementing trusted devices in Keycloak enables organizations to strike a balance between security and user convenience.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-eeb8eea elementor-widget elementor-widget-text-editor" data-id="eeb8eea" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>The trusted devices mechanism in Keycloak enhances login convenience without significantly compromising cybersecurity. Proper implementation of the device remembering policy in Keycloak helps balance system security and user experience.</p><p>However, administrators should ensure that mechanisms are in place for managing the list of trusted devices and enforcing periodic verification of their status to mitigate potential security risks.</p>						</div>
				</div>
					</div>
				</div>
		<div class="elementor-element elementor-element-9973b2a e-flex e-con-boxed e-con e-parent" data-id="9973b2a" data-element_type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-58da433 elementor-cta--skin-cover elementor-animated-content elementor-bg-transform elementor-bg-transform-zoom-in elementor-widget elementor-widget-call-to-action" data-id="58da433" data-element_type="widget" data-widget_type="call-to-action.default">
				<div class="elementor-widget-container">
					<a class="elementor-cta" href="https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ3e3C_1YeBkt1uCr_qfOnG_N298UgLFwORcSTXigrPfOk0ls3ok-Uw_dSeGCoLdtYsN13GMm-n-">
					<div class="elementor-cta__bg-wrapper">
				<div class="elementor-cta__bg elementor-bg" style="background-image: url(https://inero-software.com/wp-content/uploads/2025/02/cta-2702-1030x579.png);" role="img" aria-label="cta 2702"></div>
				<div class="elementor-cta__bg-overlay"></div>
			</div>
							<div class="elementor-cta__content">
				
									<h2 class="elementor-cta__title elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
						We will help you implement Keycloak					</h2>
				
									<div class="elementor-cta__description elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
						Want to implement Keycloak or add new functionalities? Schedule a meeting to explore the possibilities.					</div>
				
									<div class="elementor-cta__button-wrapper elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
					<span class="elementor-cta__button elementor-button elementor-size-">
						Schedule a meeting					</span>
					</div>
							</div>
						</a>
				</div>
				</div>
					</div>
				</div>
				</div>
		<p>Artykuł <a href="https://inero-software.com/trusted-devices-in-keycloak/">Trusted devices 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">7522</post-id>	</item>
		<item>
		<title>Behind the Scenes #2: Implementing email-based MFA in Keycloak</title>
		<link>https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/</link>
		
		<dc:creator><![CDATA[Marceli Formela]]></dc:creator>
		<pubDate>Thu, 13 Feb 2025 09:50:32 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Company]]></category>
		<category><![CDATA[Keycloak]]></category>
		<category><![CDATA[2FA]]></category>
		<category><![CDATA[emial]]></category>
		<category><![CDATA[IAM]]></category>
		<category><![CDATA[keycloak]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Multi-Factor Authentication]]></category>
		<category><![CDATA[OTP]]></category>
		<guid isPermaLink="false">https://inero-software.com/?p=7042</guid>

					<description><![CDATA[<p>In this post, we’ll explore a custom MFA implementation that sends a one-time authentication code to the user’s email.</p>
<p>Artykuł <a href="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/">Behind the Scenes #2: Implementing email-based MFA 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="7042" class="elementor elementor-7042" data-elementor-post-type="post">
				<div class="elementor-element elementor-element-091b893 e-flex e-con-boxed e-con e-parent" data-id="091b893" data-element_type="container">
					<div class="e-con-inner">
		<div class="elementor-element elementor-element-628ea76 e-con-full e-flex e-con e-child" data-id="628ea76" data-element_type="container">
				</div>
		<div class="elementor-element elementor-element-9ca8a9e e-con-full e-flex e-con e-child" data-id="9ca8a9e" data-element_type="container">
				<div class="elementor-element elementor-element-edd1fd0 elementor-widget elementor-widget-html" data-id="edd1fd0" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			 		</div>
				</div>
				<div class="elementor-element elementor-element-3e56066 elementor-widget elementor-widget-text-editor" data-id="3e56066" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<h5><strong>Keycloak natively supports many secure login solutions and comes with built-in one-time password (OTP) mechanisms, such as authentication via mobile apps like Google Authenticator or our solution <a href="https://inero-software.com/introducing-authm8-a-free-cross-platform-2fa-solution-tailored-to-your-brand-for-secure-authentication/">AuthM8</a>. However, if we want to use other advanced authentication methods and for example send OTP codes via email, then similar to SMS multi factor authentication (more details <a href="https://inero-software.com/custom-sms-authenticator-with-keycloak/">HERE</a>), we need to implement this functionality ourselves. In this post, we’ll explore a custom MFA implementation that sends a one-time authentication code to the user’s email. </strong></h5>						</div>
				</div>
				<div class="elementor-element elementor-element-0994f82 elementor-widget elementor-widget-heading" data-id="0994f82" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">How does email-based MFA work?
</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-8e8909e elementor-widget elementor-widget-text-editor" data-id="8e8909e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>The authentication process consists of two main stages:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8435873 elementor-widget elementor-widget-text-editor" data-id="8435873" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li><b style="color: var( --e-global-color-text ); text-align: var(--text-align);">Generating and sending the MFA code</b></li></ul></li></ul><p><span style="font-weight: 400;">If the user already has an active cookie confirming a previous MFA verification, they should be immediately authenticated. Otherwise, Keycloak creates a new credential for the user and generates a one-time code based on configurable parameters like length or time-to-live.  The code is stored in the user’s credentials and then is emailed using the email provider.</span></p><p> </p><ul><li style="list-style-type: none;"><ul><li aria-level="1"><b>Verifying the entered code</b></li></ul></li></ul><p><span style="font-weight: 400;">When a user submits the code, KC retrieves the stored credential and compares the entered value. If the code is correct and still valid (not expired), authentication is successful, and a cookie is set to remember the verification. If the code is incorrect, the user is prompted to re-enter it and if the code has expired, an error message is shown and the process must be restarted.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-d65460b elementor-widget elementor-widget-image" data-id="d65460b" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img fetchpriority="high" decoding="async" data-attachment-id="7044" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/email-based-two-factor-authentication-flowchart/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART.png" data-orig-size="1920,1080" 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="EMAIL-BASED TWO-FACTOR AUTHENTICATION FLOWCHART" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-300x169.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-1030x579.png" tabindex="0" role="button" width="1030" height="579" src="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-1030x579.png" class="attachment-large size-large wp-image-7044" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-1030x579.png 1030w, https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-300x169.png 300w, https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-768x432.png 768w, https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-1536x864.png 1536w, https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-533x300.png 533w, https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART.png 1920w" sizes="(max-width: 1030px) 100vw, 1030px" data-attachment-id="7044" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/email-based-two-factor-authentication-flowchart/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART.png" data-orig-size="1920,1080" 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="EMAIL-BASED TWO-FACTOR AUTHENTICATION FLOWCHART" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-300x169.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/EMAIL-BASED-TWO-FACTOR-AUTHENTICATION-FLOWCHART-1030x579.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-5925a75 elementor-widget elementor-widget-heading" data-id="5925a75" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default"><strong data-start="157" data-end="185">Email MFA: Pros and Cons</strong> </h3>		</div>
				</div>
				<div class="elementor-element elementor-element-3c6c4e2 elementor-widget elementor-widget-text-editor" data-id="3c6c4e2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Email-based MFA offers additional security when the primary factor, such as a password, has been compromised. This is particularly helpful in cases where passwords are brute-forced or easily guessed, such as with common combinations like 123456. Similarly, this solution offers protection against credential stuffing, where attackers use leaked passwords from other breaches to attempt logging into account.</span></p><p><span style="font-weight: 400;">There are several other benefits to using email as a MFA:</span></p><ul><li style="list-style-type: none;"><ul><li aria-level="1"><span style="font-weight: 400;">Email MFA does not require users to provide additional sensitive information, such as a phone number, reducing concerns about privacy.</span></li></ul></li></ul><ul><li style="list-style-type: none;"><ul><li aria-level="1"><span style="font-weight: 400;">It does not require users to install a separate app or complete a complicated setup, which simplifies the process.</span></li></ul></li></ul><ul><li style="list-style-type: none;"><ul><li aria-level="1"><span style="font-weight: 400;"> </span><span style="font-weight: 400;">Users are accustomed to providing their email for various purposes, such as receiving important account updates or resetting passwords. This familiarity makes it more accessible.</span></li></ul></li></ul><p><span style="font-weight: 400;">However, email as a delivery channel does have some drawbacks. If an attacker compromises your email (gains access to an email account through stolen credentials or by exploiting an active session.), they could potentially reset other accounts’ passwords as well. For users in vulnerable situations, such as those with access to shared devices, email-based MFA can still leave them exposed. As with any security measure, it’s essential to weigh the benefits against the potential risks and mix email MFA with other safeguards, such as strong passwords policy and secure email practices.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-4fd89fe elementor-widget elementor-widget-heading" data-id="4fd89fe" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Implementing Email MFA</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-cfc16d2 elementor-widget elementor-widget-image" data-id="cfc16d2" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img decoding="async" data-attachment-id="7045" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102335/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png" data-orig-size="755,508" 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="Zrzut ekranu 2025-02-13 102335" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335-300x202.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png" tabindex="0" role="button" width="755" height="508" src="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png" class="attachment-large size-large wp-image-7045" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png 755w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335-300x202.png 300w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335-446x300.png 446w" sizes="(max-width: 755px) 100vw, 755px" data-attachment-id="7045" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102335/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png" data-orig-size="755,508" 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="Zrzut ekranu 2025-02-13 102335" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335-300x202.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102335.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-295f2c1 elementor-widget elementor-widget-text-editor" data-id="295f2c1" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">In this modified Browser Authentication Flow, we integrate our custom MFA as an additional authentication method. There are two new steps:</span></p><ul><li style="list-style-type: none;"><ul><li style="font-weight: 400;" aria-level="1"><b>MFA Email setup</b><span style="font-weight: 400;"> – this step ensures that email is set up and verified for the user before proceeding. If the user does not have a custom MFA Credential (which stores OTP codes as secrets), it will be set as well.</span></li></ul></li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-1cb9fd2 elementor-widget elementor-widget-text-editor" data-id="1cb9fd2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">public class MfaEmailSetupAuthenticator implements Authenticator, CredentialValidator&lt;MfaEmailCredentialProvider&gt; {</span><br /><span style="font-weight: 400;">@Override</span><br /><span style="font-weight: 400;">public void authenticate(AuthenticationFlowContext context) {</span><br /><span style="font-weight: 400;">[…]</span><br /><span style="font-weight: 400;">// Require email verification</span><br /><span style="font-weight: 400;">if (!userModel.isEmailVerified()) {</span><br /><span style="font-weight: 400;">userModel.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);</span><br /><span style="font-weight: 400;">}</span><br /><span style="font-weight: 400;">// Add MFA email credential if not present</span><br /><span style="font-weight: 400;">if (!getCredentialProvider(context.getSession()).isConfiguredFor(realmModel, userModel, MfaEmailCredentialModel.TYPE)) {</span><br /><span style="font-weight: 400;">userModel.credentialManager().createStoredCredential(new MfaEmailCredentialModel(new MfaEmailCredentialData()));</span><br /><span style="font-weight: 400;">}</span><br /><span style="font-weight: 400;">[…]</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-6908dab elementor-widget__width-initial elementor-widget elementor-widget-image" data-id="6908dab" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img decoding="async" data-attachment-id="7046" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102520/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png" data-orig-size="635,398" 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="Zrzut ekranu 2025-02-13 102520" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520-300x188.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png" tabindex="0" role="button" width="635" height="398" src="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png" class="attachment-large size-large wp-image-7046" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png 635w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520-300x188.png 300w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520-479x300.png 479w" sizes="(max-width: 635px) 100vw, 635px" data-attachment-id="7046" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102520/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png" data-orig-size="635,398" 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="Zrzut ekranu 2025-02-13 102520" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520-300x188.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102520.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-eafd6c8 elementor-widget elementor-widget-text-editor" data-id="eafd6c8" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li style="font-weight: 400;" aria-level="1"><b>MFA Email Authentication</b><span style="font-weight: 400;"> – this is the actual authentication step where a one-time code is sent via email. Marked as Alternative, meaning it can be used instead of other MFA methods like mobile app OTP.</span></li></ul></li></ul><p><span style="font-weight: 400;">Here, you can see how the configuration of this authenticator could look like in the Keycloak authentication flow.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-bdcf27f elementor-widget__width-initial elementor-widget elementor-widget-image" data-id="bdcf27f" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" data-attachment-id="7047" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102652/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png" data-orig-size="473,622" 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="Zrzut ekranu 2025-02-13 102652" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652-228x300.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png" tabindex="0" role="button" width="473" height="622" src="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png" class="attachment-large size-large wp-image-7047" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png 473w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652-228x300.png 228w" sizes="(max-width: 473px) 100vw, 473px" data-attachment-id="7047" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-102652/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png" data-orig-size="473,622" 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="Zrzut ekranu 2025-02-13 102652" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652-228x300.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-102652.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-10b800d elementor-widget elementor-widget-text-editor" data-id="10b800d" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul><li style="list-style-type: none;"><ul><li style="font-weight: 400;" aria-level="1"><b>Max Cookie Age</b><span style="font-weight: 400;"> this setting determines how long the MFA session (cookie) is valid. If the cookie is still valid, the user won&#8217;t be prompted for MFA. </span></li><li style="font-weight: 400;" aria-level="1"><b>Time-to-live</b><span style="font-weight: 400;"> indicates the lifetime of the MFA code.</span></li></ul></li></ul><p> </p><p><span style="font-weight: 400;">Now let’s take a look at the code. </span></p><p> </p><p><span style="font-weight: 400;">The method below handles the MFA process itself. If a valid cookie exists (indicating that the user has already completed MFA), the method immediately returns success, meaning the authentication flow is complete without requiring additional actions.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-89fa524 elementor-widget elementor-widget-text-editor" data-id="89fa524" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">@Override</span><br /><span style="font-weight: 400;">public void authenticate(AuthenticationFlowContext context) {</span><br /><span style="font-weight: 400;">if (hasValidCookie(context)) {</span><br /><span style="font-weight: 400;">context.success();</span><br /><span style="font-weight: 400;">return;</span><br /><span style="font-weight: 400;">}</span><br /><span style="font-weight: 400;">[…]</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-55ff859 elementor-widget elementor-widget-text-editor" data-id="55ff859" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">If there is no cookie, we should try to retrieve the user’s existing MFA credential from the credential provider. If the user doesn’t have one, a new instance is created using the MfaEmailCredentialModel which just extends the built-in CredentialModel:</span><span style="font-weight: 400;"><br /></span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-0af0624 elementor-widget elementor-widget-text-editor" data-id="0af0624" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">[…]</span><br /><span style="font-weight: 400;">// get existing credential or create a new one</span><br /><span style="font-weight: 400;">CredentialModel credentialModel = getCredentialProvider(session)</span><br /><span style="font-weight: 400;">.getDefaultCredential(session, context.getRealm(), user);</span><br /><span style="font-weight: 400;">if (credentialModel == null) {</span><br /><span style="font-weight: 400;">credentialModel = user.credentialManager().createStoredCredential(new MfaEmailCredentialModel(new MfaEmailCredentialData()));</span><br /><span style="font-weight: 400;">}</span><br /><span style="font-weight: 400;">[…]</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-c7af14a elementor-widget elementor-widget-text-editor" data-id="c7af14a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Then the authenticate method reads configuration properties like code length and TTL (time-to-live). The code itself can be generated using some utils method and will be stored as the secretData in the credential model.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-6551375 elementor-widget elementor-widget-text-editor" data-id="6551375" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">// generate and store code</span><br /><span style="font-weight: 400;">int length = Integer.parseInt(configMap.get(CONFIG_CODE_LENGTH));</span><br /><span style="font-weight: 400;">int ttl = Integer.parseInt(configMap.get(CONFIG_CODE_TTL));</span><br /><span style="font-weight: 400;">String code = MfaEmailCodesUtils.generateCode(length);</span><br /><span style="font-weight: 400;">credentialModel.setSecretData(code);</span><br /><span style="font-weight: 400;">user.credentialManager().updateStoredCredential(credentialModel);</span><br /><span style="font-weight: 400;">AuthenticationSessionModel authSession = context.getAuthenticationSession();</span><br /><span style="font-weight: 400;">authSession.setAuthNote("ttl", Long.toString(System.currentTimeMillis() + (ttl * 1000L)));</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-b7f4d62 elementor-widget elementor-widget-text-editor" data-id="b7f4d62" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">In the end the sendCode method is called to send the generated code to the user’s email. If the email is sent successfully, the method presents the form where the user can enter the MFA code.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-dc63501 elementor-widget elementor-widget-text-editor" data-id="dc63501" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">// send email and show input form</span><br /><span style="font-weight: 400;">try {</span><br /><span style="font-weight: 400;">MfaEmailCodesUtils.sendCode(session, user, ttl, code, configMap);</span><br /><span style="font-weight: 400;">context.challenge(context.form().setAttribute("realm", context.getRealm()).createForm(TPL_CODE));</span><br /><span style="font-weight: 400;">} catch (Exception e) {</span><br /><span style="font-weight: 400;">context.failureChallenge(AuthenticationFlowError.INTERNAL_ERROR,</span><br /><span style="font-weight: 400;">context.form().setError("mfaEmailNotSent", e.getMessage())  .createErrorPage(Response.Status.INTERNAL_SERVER_ERROR));</span><br /><span style="font-weight: 400;">}</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-b41ad7b elementor-widget elementor-widget-text-editor" data-id="b41ad7b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">The second major part of our Authenticator is the action method which handles the validation of the code entered by the user. It is invoked when the user submits the input form after receiving the email.  </span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-9551f9f elementor-widget__width-initial elementor-widget elementor-widget-image" data-id="9551f9f" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" data-attachment-id="7048" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-103114/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png" data-orig-size="663,391" 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="Zrzut ekranu 2025-02-13 103114" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114-300x177.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png" tabindex="0" role="button" width="663" height="391" src="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png" class="attachment-large size-large wp-image-7048" alt="" srcset="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png 663w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114-300x177.png 300w, https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114-509x300.png 509w" sizes="(max-width: 663px) 100vw, 663px" data-attachment-id="7048" data-permalink="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/zrzut-ekranu-2025-02-13-103114/" data-orig-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png" data-orig-size="663,391" 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="Zrzut ekranu 2025-02-13 103114" data-image-description="" data-image-caption="" data-medium-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114-300x177.png" data-large-file="https://inero-software.com/wp-content/uploads/2025/02/Zrzut-ekranu-2025-02-13-103114.png" role="button" />													</div>
				</div>
				<div class="elementor-element elementor-element-460cfb7 elementor-widget elementor-widget-text-editor" data-id="460cfb7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">The method retrieves the user’s credential from the provider and then the code is validated by checking it against the stored credential using the custom isValid method.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-ff19a7e elementor-widget elementor-widget-text-editor" data-id="ff19a7e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">[…]</span><br /><span style="font-weight: 400;">final MfaEmailCredentialModel credentialModel = getCredentialProvider(session)</span><br /><span style="font-weight: 400;">        .getDefaultCredential(session, context.getRealm(), user);</span><br /><span style="font-weight: 400;">boolean isValid = getCredentialProvider(session).isValid(context.getRealm(), user,</span><br /><span style="font-weight: 400;">    </span> <span style="font-weight: 400;">new UserCredentialModel(credentialModel.getId(), getCredentialProvider(context.getSession()).getType(), enteredCode));</span><br /><span style="font-weight: 400;">[…]</span></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-7b502f8 elementor-widget elementor-widget-text-editor" data-id="7b502f8" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">If the code is valid, the next step is to check if it is expired. We can also set a cookie that stores the MFA session to prevent the user from </span><b>being prompted for MFA again</b><span style="font-weight: 400;"> during the cookie’s validity period.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-3db7437 elementor-widget elementor-widget-text-editor" data-id="3db7437" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><span style="font-weight: 400;">[…]</span><br /><span style="font-weight: 400;">// valid</span><br /><span style="font-weight: 400;">HttpResponse response = context.getSession().getContext().getHttpResponse();</span><br /><span style="font-weight: 400;">response.setCookieIfAbsent(createCookie(context));</span><br /><span style="font-weight: 400;">context.success();</span><br /><span style="font-weight: 400;">[…]</span></pre><p><span style="font-weight: 400;"> </span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-83cf638 elementor-widget elementor-widget-text-editor" data-id="83cf638" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="font-weight: 400;">Of course, in this post, we will not cover the entire topic, omitting implementation details such as sending the code, generating the code, validation, and creating our custom cookie.</span></p><p><span style="font-weight: 400;"><br></span></p>
<p><span style="font-weight: 400;">However, we have walked through the major steps of implementing 2FA using email-based codes. On the one hand, this approach offers a simple and accessible solution. Although it has its drawbacks, using it in solutions like Keycloak helps mitigate many of these vulnerabilities. Keycloak also provides the flexibility to combine email-based MFA with other security measures, creating a more layered and resilient authentication process that can help protect against evolving cybersecurity threats.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-a27180c elementor-cta--skin-cover elementor-animated-content elementor-bg-transform elementor-bg-transform-zoom-in elementor-widget elementor-widget-call-to-action" data-id="a27180c" data-element_type="widget" data-widget_type="call-to-action.default">
				<div class="elementor-widget-container">
					<div class="elementor-cta">
					<div class="elementor-cta__bg-wrapper">
				<div class="elementor-cta__bg elementor-bg" style="background-image: url(https://inero-software.com/wp-content/uploads/2024/11/tlo-popup-keycloak-1030x731.png);" role="img" aria-label="tło popup keycloak"></div>
				<div class="elementor-cta__bg-overlay"></div>
			</div>
							<div class="elementor-cta__content">
				
									<h3 class="elementor-cta__title elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
						Do you need help configuring multi-factor authentication?					</h3>
				
									<div class="elementor-cta__description elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
						Schedule a meeting to find out how we can help you.					</div>
				
									<div class="elementor-cta__button-wrapper elementor-cta__content-item elementor-content-item elementor-animated-item--grow">
					<a class="elementor-cta__button elementor-button elementor-size-" href="https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ3e3C_1YeBkt1uCr_qfOnG_N298UgLFwORcSTXigrPfOk0ls3ok-Uw_dSeGCoLdtYsN13GMm-n-">
						Schedule a meeting					</a>
					</div>
							</div>
						</div>
				</div>
				</div>
				</div>
		<div class="elementor-element elementor-element-6bc7752 e-con-full e-flex e-con e-child" data-id="6bc7752" data-element_type="container">
				</div>
					</div>
				</div>
		<div class="elementor-element elementor-element-091ddaf e-flex e-con-boxed e-con e-parent" data-id="091ddaf" data-element_type="container">
					<div class="e-con-inner">
					</div>
				</div>
				</div>
		<p>Artykuł <a href="https://inero-software.com/behind-the-scenes-2-implementing-email-based-mfa-in-keycloak/">Behind the Scenes #2: Implementing email-based MFA 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">7042</post-id>	</item>
	</channel>
</rss>
