Back to: ASP.NET Core Identity Tutorials
Email Confirmation in ASP.NET Core Identity
In this article, I will discuss Email Confirmation in ASP.NET Core Identity, i.e., How to Confirm Email in ASP.NET Core Identity. Please read our previous article discussing Configuring Email Service in ASP.NET Core.
Why is Email Confirmation Important?
When registering for an account with a website, we provide our email address. Upon registration, an email with a link is sent, which we should click to confirm that the provided email really belongs to us.
Until the email address is confirmed, your account will have limited functionality. Some websites might block you from signing in until the email address is confirmed. Letting users log in without a confirmed email is a security risk. Email confirmation is essential for your security and the application’s security.
For example, a user registered with our application using the email john@example.com. His email is jon@example.com, but it does not have the letter h. He made a typo and accidentally included the letter h in his email (john@example.com). Our application allowed the user to log in and set up his account by providing all the personal, financial, and other required details. This user uses the application normally, and there is no problem.
After a few days, another user who owns the email john@example.com (with the letter h in the email) tries to register with our application. He cannot proceed with the registration as his email is already being used. So, he requests a password reset link, which will be sent to his email. He clicks on the link and changes the password.
There are two problems here.
- The first user can no longer log in as the password changes.
- When the second user logs in, he will have access to the first user’s personal, financial, and other details.
This is a huge concern from a security standpoint. The second user can hijack the first user’s account. We wouldn’t have been in this situation if the email was confirmed upon registration.
Account Confirmation Flow in Web Application:
Implementing email confirmation functionality in an ASP.NET Core Identity application involves several steps, including sending a confirmation email, creating a view for email confirmation, and handling the confirmation logic. The following is the Registration Page. The User needs to provide the details and click the Register button, as shown in the image below.
When the user clicks on the Register button, it will create a new user in the AspNetUsers table and display the following message.
Now, if you verify the AspNetUsers table, you will see that the user is created, but the EmailConfirmed property value is 0, as shown in the image below.
Now, check your Email ID. The confirmation email should be sent, and if you open the email, then you will see the following:
Once you click the above button or link, the account should be confirmed, and you will get the following message.
Now, if you check the AspNetUsers table, then you will see that EmailConfirmed property value must be set to 1 as shown in the below image.
Resend Confirmation Email:
Clicking on the Resend Confirmation Email from the Registration Successful Page will open the page below and ask you to enter your Email ID.
Once you enter the email ID and press the Resend Confirmation Email button, the account confirmation link will be resent to the above email ID if it exists in the database. Then, the following message will be displayed:
Let us proceed and see how to implement the above functionalities in our ASP.NET Core project step by step.
Add ASP.NET Core Default Token Providers
First, we need to configure the token provider to generate the token. In the Program class, call the AddDefaultTokenProviders() method to add the ASP.NET Core default token providers that generate email confirmation tokens, password reset tokens, two-factor authentication, etc. So, please modify the AddIdentity service as follows:
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>( options => { // Password settings options.Password.RequireDigit = true; options.Password.RequiredLength = 8; options.Password.RequireNonAlphanumeric = true; options.Password.RequireUppercase = true; options.Password.RequireLowercase = true; options.Password.RequiredUniqueChars = 4; }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); // Adding Default Token Provider for ASP.NET Core Identity
Initialize the EmailSender Service in Account Controller:
We have already created the Email Sender service to send the email. So, create a variable of IEmailSenderService service type and then initialize that variable through the constructor of Account Controller as follows:
public class AccountController : Controller { //userManager will hold the UserManager instance private readonly UserManager<ApplicationUser> userManager; //signInManager will hold the SignInManager instance private readonly SignInManager<ApplicationUser> signInManager; //EmailSenderService will hold the EmailSenderService instance private readonly EmailSenderService emailSender; //UserManager, SignInManager and EmailSenderService services are injected into the AccountController // using constructor injection public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, EmailSenderService emailSender) { this.userManager = userManager; this.signInManager = signInManager; this.emailSender = emailSender; } //Rest of All Codes }
Creating a Private Method to Send Confirmation Email:
Please add the following SendConfirmationEmail private method to the Account Controller, which will send the confirmation email to the user.
private async Task SendConfirmationEmail(string email, ApplicationUser user) { // Generate the email confirmation token var token = await userManager.GenerateEmailConfirmationTokenAsync(user); // Build the confirmation callback URL var confirmationLink = Url.Action("ConfirmEmail", "Account", new { UserId = user.Id, Token = token }, protocol: HttpContext.Request.Scheme); // Encode the link to prevent XSS and other injection attacks var safeLink = HtmlEncoder.Default.Encode(confirmationLink); // Craft a more polished email subject var subject = "Welcome to Dot Net Tutorials! Please Confirm Your Email"; // Create a professional HTML body // Customize inline styles, text, and branding as needed var messageBody = $@" <div style=""font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.6;color:#333;""> <p>Hi {user.FirstName} {user.LastName},</p> <p>Thank you for creating an account at <strong>Dot Net Tutorials</strong>. To start enjoying all of our features, please confirm your email address by clicking the button below:</p> <p> <a href=""{safeLink}"" style=""background-color:#007bff;color:#fff;padding:10px 20px;text-decoration:none; font-weight:bold;border-radius:5px;display:inline-block;""> Confirm Email </a> </p> <p>If the button doesn’t work for you, copy and paste the following URL into your browser: <br /> <a href=""{safeLink}"" style=""color:#007bff;text-decoration:none;"">{safeLink}</a> </p> <p>If you did not sign up for this account, please ignore this email.</p> <p>Thanks,<br /> The Dot Net Tutorials Team</p> </div> "; //Send the Confirmation Email to the User Email Id await emailSender.SendEmailAsync(email, subject, messageBody, true); }
Modifying the Register Post Action Method of Account Controller:
Open Successful Registration, we need to send the Confirmation Email. Then we need to redirect to the Successful User Registration Page and show the message that your registration is successful if the user is not admin. So, modify the Register Post Action Method of the Account Controller as follows:
[HttpPost] [AllowAnonymous] public async Task<IActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { // Copy data from RegisterViewModel to IdentityUser var user = new ApplicationUser { FirstName = model.FirstName, LastName = model.LastName, UserName = model.Email, Email = model.Email }; // Store user data in AspNetUsers database table var result = await userManager.CreateAsync(user, model.Password); // If user is successfully created, sign-in the user using // SignInManager and redirect to index action of HomeController if (result.Succeeded) { //Then send the Confirmation Email to the User await SendConfirmationEmail(model.Email, user); // If the user is signed in and in the Admin role, then it is // the Admin user that is creating a new user. // So, redirect the Admin user to ListUsers action of Administration Controller if (signInManager.IsSignedIn(User) && User.IsInRole("Admin")) { return RedirectToAction("ListUsers", "Administration"); } //If it is not Admin user, then redirect the user to RegistrationSuccessful View return View("RegistrationSuccessful"); } // If there are any errors, add them to the ModelState object // which will be displayed by the validation summary tag helper foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } return View(model); }
Registration Successful View:
Once the User is registered, we need to redirect the user to the RegistrationSuccessful view. So, create a view with the name RegistrationSuccessful.cshtml within the Views/Shared folder and then copy and paste the following code:
@{ ViewData["Title"] = "Registration Successful"; } <div class="container mt-5"> <div class="row"> <div class="col-md-8 offset-md-2"> <div class="card shadow"> <div class="card-header"> <h3 class="card-title mb-0"> Registration Successful </h3> </div> <div class="card-body"> <p> Thank you for signing up with <strong>Dot Net Tutorials</strong>! We appreciate your interest in our services. Before you can log in, please confirm your email address by clicking on the verification link that was sent to your email inbox. </p> <p> If you can’t find the confirmation email or the link has expired, you can request another verification link below: </p> <a class="btn btn-primary" asp-controller="Account" asp-action="ResendConfirmationEmail"> Resend Confirmation Email </a> </div> </div> </div> </div> </div>
In the above view, we are displaying a message to the user that registration is successful, but before logging in, you need to confirm your email address by clicking on the link sent to your email ID. We have also provided one button to resend the email confirmation link.
Create Confirm Email Action Method
Create an action method in the Account Controller to handle email confirmation. This callback action method will be invoked whenever the user clicks the link sent to his/her email address. So, please add the following ConfirmEmail action method in your Account Controller.
[HttpGet] [AllowAnonymous] public async Task<IActionResult> ConfirmEmail(string UserId, string Token) { if (string.IsNullOrEmpty(UserId) || string.IsNullOrEmpty(Token)) { // Provide a descriptive error message for the view ViewBag.ErrorMessage = "The link is invalid or has expired. Please request a new one if needed."; return View(); } //Find the User by Id var user = await userManager.FindByIdAsync(UserId); if (user == null) { // Provide a descriptive error for a missing user scenario ViewBag.ErrorMessage = "We could not find a user associated with the given link."; return View(); } // Attempt to confirm the email var result = await userManager.ConfirmEmailAsync(user, Token); if (result.Succeeded) { ViewBag.Message = "Thank you for confirming your email address. Your account is now verified!"; return View(); } // If confirmation fails ViewBag.ErrorMessage = "We were unable to confirm your email address. Please try again or request a new link."; return View(); }
Note: If the user exists and the token is valid, then the ConfirmEmailAsync method will update the EmailConfirmed column value to 1, which means the email is confirmed.
Create Confirm Email View
Next, create a view with the name ConfirmEmail.cshtml within the Views/Account folder and copy and paste the following code.
@{ ViewData["Title"] = "Email Confirmation"; var error = ViewBag.ErrorMessage as string; var success = ViewBag.Message as string; } <div class="container mt-5"> <div class="row"> <div class="col-md-8 offset-md-2"> <div class="card shadow"> <div class="card-header"> <h3 class="card-title mb-0">Email Confirmation</h3> </div> <div class="card-body"> @* If there is a success message, display a success alert *@ @if (!string.IsNullOrEmpty(success)) { <div class="alert alert-success" role="alert"> <strong>Success!</strong> @success </div> <p> You can now <strong> <a href="@Url.Action("Login", "Account")" class="font-weight-bold">Login</a> </strong> and start using all the features of <strong>Dot Net Tutorials</strong>. We’re excited to have you onboard! </p> } @* Otherwise, if there’s an error message, display an error alert *@ else if (!string.IsNullOrEmpty(error)) { <div class="alert alert-danger" role="alert"> <strong>Oops!</strong> @error </div> <p> If the link has expired or you never received one, you can <a href="@Url.Action("ResendConfirmationEmail", "Account")" class="font-weight-bold"> request a new confirmation email </a> at any time. </p> } </div> </div> </div> </div> </div>
ResendConfirmationEmail Get Action Method
In the RegistrationSuccessful view, we have provided the Resend Email button. Add the following ResendConfirmationEmail GET Action method within the Account Controller, which will be invoked when the user clicks the Resend Email button. This method will render the Resend Account Confirmation Email view, where the user will enter his email to resend the confirmation email.
[HttpGet] [AllowAnonymous] public IActionResult ResendConfirmationEmail(bool IsResend = true) { if (IsResend) { ViewBag.Message = "Resend Confirmation Email"; } else { ViewBag.Message = "Send Confirmation Email"; } return View(); }
Note: We will use the above action method and the following view for Resend and Send Email Confirmation Email purposes, and the IsResend parameter value will decide this.
ResendConfirmationEmail View:
Next, create a view with the name ResendConfirmationEmail.cshtml within the Views/Account folder and then copy and paste the following code:
@{ ViewData["Title"] = ViewBag.Message ?? "Resend Confirmation Email"; } <div class="container mt-5"> <div class="row"> <div class="col-md-6 offset-md-3"> <!-- Display the Page Message --> <h2 class="text-center mb-4">@ViewBag.Message</h2> <!-- Card for the Resend Confirmation Form --> <div class="card shadow"> <div class="card-body"> <p class="lead"> If you haven't received your confirmation email, please enter your email address below. We'll send you another link to verify your account. </p> <form asp-action="ResendConfirmationEmail" asp-controller="Account" method="post"> <div class="form-group mb-3"> <label for="emailInput" class="form-label">Email Address</label> <input type="email" id="emailInput" name="email" class="form-control" placeholder="yourname@example.com" required /> </div> <button class="btn btn-primary" type="submit">@ViewBag.Message</button> </form> </div> </div> </div> </div> </div>
ResendConfirmationEmail Post Action Method
First, we need to find the user by their email or username. If the email has already been confirmed, redirect the user or inform them accordingly. If the email is not confirmed, generate a new confirmation token and send it via email. So, please add the following ResendConfirmationEmail Post Action method within the Account Controller.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<IActionResult> ResendConfirmationEmail(string Email) { var user = await userManager.FindByEmailAsync(Email); if (user == null || await userManager.IsEmailConfirmedAsync(user)) { // Handle the situation when the user does not exist or Email already confirmed. // For security, don't reveal that the user does not exist or Email is already confirmed return View("ConfirmationEmailSent"); } //Then send the Confirmation Email to the User await SendConfirmationEmail(Email, user); return View("ConfirmationEmailSent"); }
ConfirmationEmailSent View:
Create a view named ConfirmationEmailSent.cshtml within the Views/Shared directory, and then copy and paste the following code:
@{ ViewData["Title"] = "Confirmation Email Sent"; } <div class="container mt-5"> <div class="row"> <div class="col-md-8 offset-md-2"> <div class="card shadow"> <div class="card-header"> <h2 class="card-title mb-0">Confirmation Email Sent</h2> </div> <div class="card-body"> <p> If an account exists with the email address you provided, a confirmation link has been sent to that inbox. Please check your spam folder if you do not see it within a few minutes or <a asp-action="ResendConfirmationEmail" asp-controller="Account">click here</a> to resend the confirmation email. </p> <p> If you have any questions or need further assistance, feel free to <a href="@Url.Action("Contact", "Home")">contact our support team</a>. </p> </div> </div> </div> </div> </div>
That’s it. Run the application and test the functionality; it should work as expected.
Why Email Confirmed is Required in ASP.NET Core Identity?
Email confirmation in web applications is a common requirement to ensure security, verify the authenticity of users, and provide better control over account access. The following are the key reasons why this approach is implemented:
- Preventing Unauthorized Access: Stops attackers from using someone else’s email to create accounts. Until the email is confirmed, the account is not fully activated. This prevents misuse by unauthorized users. For example, an attacker might use an email they do not own, and without email confirmation, the real email owner could be inconvenienced or compromised.
- Reducing Spam Accounts: Reduces the risk of automated bots or malicious users creating fake accounts. Email confirmation acts as a basic hurdle for such activities, ensuring that only legitimate users can complete the signup process.
- Enhanced Security: Provides an additional layer of security by ensuring a valid communication channel. This is especially important for critical actions like password recovery, two-factor authentication, and receiving account-related notifications.
In the next article, I will discuss How to Block Login if Email is not Confirmed in ASP.NET Core Identity. In this article, I explain How to Implement Email Confirmation in ASP.NET Core Identity. I hope you enjoy this article, Email Confirmation in ASP.NET Core Identity.