Uh oh!
+Email confirmation failed. Please try again!
+{{errors}}
+From bb008c032d7ab692622103d0b527726359b807a6 Mon Sep 17 00:00:00 2001 From: 01zulfi <85733202+01zulfi@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:27:42 +0500 Subject: [PATCH] identity: render HTML pages for email confirmation outcomes (#89) --- .../Controllers/AccountController.cs | 26 ++- .../Templates/EmailConfirmErrorPage.html | 128 +++++++++++ .../Templates/EmailConfirmedPage.html | 213 ++++++++++++++++++ 3 files changed, 363 insertions(+), 4 deletions(-) create mode 100644 Streetwriters.Identity/Templates/EmailConfirmErrorPage.html create mode 100644 Streetwriters.Identity/Templates/EmailConfirmedPage.html diff --git a/Streetwriters.Identity/Controllers/AccountController.cs b/Streetwriters.Identity/Controllers/AccountController.cs index 05ab2f1..07f74c0 100644 --- a/Streetwriters.Identity/Controllers/AccountController.cs +++ b/Streetwriters.Identity/Controllers/AccountController.cs @@ -34,6 +34,7 @@ using Microsoft.AspNetCore.RateLimiting; using Microsoft.Extensions.Logging; using Streetwriters.Common; using Streetwriters.Common.Enums; +using Streetwriters.Common.Helpers; using Streetwriters.Common.Interfaces; using Streetwriters.Common.Messages; using Streetwriters.Common.Models; @@ -52,6 +53,9 @@ namespace Streetwriters.Identity.Controllers [Authorize(LocalApi.PolicyName)] public class AccountController : IdentityControllerBase { + private static readonly string emailConfirmedPageHtml = HtmlHelper.ReadMinifiedHtmlFile("Templates/EmailConfirmedPage.html"); + private static readonly string emailConfirmErrorPageHtml = HtmlHelper.ReadMinifiedHtmlFile("Templates/EmailConfirmErrorPage.html"); + private IPersistedGrantStore PersistedGrantStore { get; set; } private ITokenGenerationService TokenGenerationService { get; set; } private IUserAccountService UserAccountService { get; set; } @@ -93,10 +97,22 @@ namespace Streetwriters.Identity.Controllers { case TokenType.CONFRIM_EMAIL: { - if (await UserManager.IsEmailConfirmedAsync(user)) return Ok("Email already verified."); + if (await UserManager.IsEmailConfirmedAsync(user)) + { + return Content( + emailConfirmedPageHtml.Replace("{{subheading}}", "Your email is already verified."), + "text/html" + ); + } var result = await UserManager.ConfirmEmailAsync(user, code); - if (!result.Succeeded) return BadRequest(result.Errors.ToErrors()); + if (!result.Succeeded) + { + return Content( + emailConfirmErrorPageHtml.Replace("{{errors}}", string.Join(" ", result.Errors.ToErrors())), + "text/html" + ); + } if (await UserManager.IsInRoleAsync(user, client.Id) && client.OnEmailConfirmed != null) { @@ -106,8 +122,10 @@ namespace Streetwriters.Identity.Controllers if (!await UserManager.GetTwoFactorEnabledAsync(user)) await MFAService.EnableMFAAsync(user, MFAMethods.Email); - var redirectUrl = $"{client.EmailConfirmedRedirectURL}?userId={userId}"; - return RedirectPermanent(redirectUrl); + return Content( + emailConfirmedPageHtml.Replace("{{subheading}}", "Your email has been confirmed."), + "text/html" + ); } case TokenType.RESET_PASSWORD: { diff --git a/Streetwriters.Identity/Templates/EmailConfirmErrorPage.html b/Streetwriters.Identity/Templates/EmailConfirmErrorPage.html new file mode 100644 index 0000000..2cb2594 --- /dev/null +++ b/Streetwriters.Identity/Templates/EmailConfirmErrorPage.html @@ -0,0 +1,128 @@ + + +
+ + +Email confirmation failed. Please try again!
+{{errors}}
+{{subheading}}
++ Thank you for choosing end-to-end encrypted note taking. Now you can + sync your notes to unlimited devices. +
+