From 5139c94f709f8d545a6b9254691f14c183b267ba Mon Sep 17 00:00:00 2001 From: Geremia Taglialatela Date: Sun, 8 Feb 2026 19:08:07 +0100 Subject: [PATCH] Fix duplicate header in VERIFY_EMAIL flow When executing the VERIFY_EMAIL action (for example via the admin API), the confirmation page showed "Your account has been updated." twice, once as the page header and once as the body. The root cause is that `AuthenticationManager.finishedRequiredActions()` rendered the `ACCOUNT_UPDATED` info page without setting a messageHeader attribute. The `info.ftl` template falls back to `message.summary` when `messageHeader` is not set, which produced the duplicated message. Change summary: - Add a new message key `accountUpdatedTitle` with value "Account Updated". - Add a Messages constant (`ACCOUNT_UPDATED_TITLE`) for the new key. - Update `AuthenticationManager` to set the `messageHeader` attribute to the message key (`ACCOUNT_UPDATED_TITLE`) instead of passing a resolved message string. Passing the key lets the template render a distinct header (localized via the message key) and keeps the body message separate. Result: - Header now reads "Account Updated" - Body now reads "Your account has been updated." - Prevents the same message appearing both in the header and the body. Notes: - This addresses the same underlying issue reported in #41701 Fix #46105 Signed-off-by: Geremia Taglialatela Update tests to expect new "Account Updated" page title Updated UserEmailTest assertions to expect "Account Updated" instead of "Your account has been updated." for the kc-page-title element (header). The body message still shows "Your account has been updated." - only the header was changed to be shorter and more concise. Fixed tests: - sendResetPasswordEmailWithRedirect (line 617) - sendResetPasswordEmailWithRedirectAndCustomLifespan (line 699) Co-authored-by: tagliala <556268+tagliala@users.noreply.github.com> Lowercase message --- .../org/keycloak/services/managers/AuthenticationManager.java | 1 + .../main/java/org/keycloak/services/messages/Messages.java | 2 ++ .../java/org/keycloak/tests/admin/user/UserEmailTest.java | 4 ++-- .../theme/base/login/messages/messages_en.properties | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 5ff72ff6addb..bd98c0afbc20 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -1088,6 +1088,7 @@ public static Response finishedRequiredActions(KeycloakSession session, Authenti if (authSession.getAuthNote(END_AFTER_REQUIRED_ACTIONS) != null) { LoginFormsProvider infoPage = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession) + .setAttribute("messageHeader", Messages.ACCOUNT_UPDATED_TITLE) .setSuccess(Messages.ACCOUNT_UPDATED); if (authSession.getAuthNote(SET_REDIRECT_URI_AFTER_REQUIRED_ACTIONS) != null) { if (authSession.getRedirectUri() != null) { diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java index a3e4de7edc97..710ec6f82e28 100755 --- a/services/src/main/java/org/keycloak/services/messages/Messages.java +++ b/services/src/main/java/org/keycloak/services/messages/Messages.java @@ -140,6 +140,8 @@ public class Messages { public static final String ACCOUNT_UPDATED = "accountUpdatedMessage"; + public static final String ACCOUNT_UPDATED_TITLE = "accountUpdatedTitle"; + public static final String ACCOUNT_PASSWORD_UPDATED = "accountPasswordUpdatedMessage"; public static final String NO_ACCESS = "noAccessMessage"; diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/user/UserEmailTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/user/UserEmailTest.java index e0279d552092..3b4a568cee26 100644 --- a/tests/base/src/test/java/org/keycloak/tests/admin/user/UserEmailTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/admin/user/UserEmailTest.java @@ -614,7 +614,7 @@ public void sendResetPasswordEmailWithRedirect() throws IOException { passwordUpdatePage.changePassword("new-pass", "new-pass"); - assertEquals("Your account has been updated.", driver.findElement(By.id("kc-page-title")).getText()); + assertEquals("Account updated", driver.findElement(By.id("kc-page-title")).getText()); String pageSource = driver.page().getPageSource(); @@ -696,7 +696,7 @@ public void sendResetPasswordEmailWithRedirectAndCustomLifespan() throws IOExcep passwordUpdatePage.changePassword("new-pass", "new-pass"); - assertEquals("Your account has been updated.", driver.findElement(By.id("kc-page-title")).getText()); + assertEquals("Account updated", driver.findElement(By.id("kc-page-title")).getText()); String pageSource = driver.page().getPageSource(); diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties index c347d4e80c97..2cb321c801af 100644 --- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties @@ -311,6 +311,7 @@ linkIdpMessage=You need to verify your email address to link your account with { emailSentMessage=You should receive an email shortly with further instructions. emailSendErrorMessage=Failed to send email, please try again later. +accountUpdatedTitle=Account updated accountUpdatedMessage=Your account has been updated. accountPasswordUpdatedMessage=Your password has been updated.