2016-10-29 01:35:15 +08:00
---
2018-03-22 08:18:35 +08:00
title: Account confirmation and password recovery in ASP.NET Core
2016-10-29 01:35:15 +08:00
author: rick-anderson
2018-02-13 06:22:43 +08:00
description: Learn how to build an ASP.NET Core app with email confirmation and password reset.
2016-10-29 01:35:15 +08:00
manager: wpickett
2018-01-29 23:21:31 +08:00
ms.author: riande
2018-02-13 06:22:43 +08:00
ms.date: 2/11/2018
2017-03-03 08:50:36 +08:00
ms.prod: asp.net-core
2018-01-29 23:21:31 +08:00
ms.technology: aspnet
ms.topic: article
2016-10-29 01:35:15 +08:00
uid: security/authentication/accconfirm
---
2017-07-25 01:41:58 +08:00
# Account confirmation and password recovery in ASP.NET Core
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
By [Rick Anderson ](https://twitter.com/RickAndMSFT ) and [Joe Audette ](https://twitter.com/joeaudette )
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
This tutorial shows you how to build an ASP.NET Core app with email confirmation and password reset. This tutorial is **not** a beginning topic. You should be familiar with:
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
* [ASP.NET Core ](xref:tutorials/first-mvc-app/start-mvc )
* [Authentication ](xref:security/authentication/index )
* [Account Confirmation and Password Recovery ](xref:security/authentication/accconfirm )
* [Entity Framework Core ](xref:data/ef-mvc/intro )
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
See [this PDF file ](https://github.com/aspnet/Docs/tree/master/aspnetcore/security/authorization/secure-data/asp.net_repo_pdf_1-16-18.pdf ) for the ASP.NET Core MVC 1.1 and 2.x versions.
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
## Prerequisites
2017-07-25 01:41:58 +08:00
2018-04-05 07:51:35 +08:00
[!INCLUDE [ ](~/includes/net-core-prereqs.md )]
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
## Create a new ASP.NET Core project with the .NET Core CLI
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x)
2016-10-29 01:35:15 +08:00
2018-05-31 03:48:08 +08:00
::: moniker range=">= aspnetcore-2.1"
```console
dotnet new webapp --auth Individual -o WebPWrecover
cd WebPWrecover
```
::: moniker-end
::: moniker range="= aspnetcore-2.0"
2018-02-13 06:22:43 +08:00
```console
dotnet new razor --auth Individual -o WebPWrecover
cd WebPWrecover
```
2016-10-29 01:35:15 +08:00
2018-05-31 03:48:08 +08:00
::: moniker-end
2018-02-13 06:22:43 +08:00
* `--auth Individual` specifies the Individual User Accounts project template.
* On Windows, add the `-uld` option. It specifies LocalDB should be used instead of SQLite.
* Run `new mvc --help` to get help on this command.
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x)
2017-07-25 01:41:58 +08:00
If you're using the CLI or SQLite, run the following in a command window:
```console
dotnet new mvc --auth Individual
```
2018-02-13 06:22:43 +08:00
* `--auth Individual` specifies the Individual User Accounts project template.
* On Windows, add the `-uld` option. It specifies LocalDB should be used instead of SQLite.
2017-07-25 01:41:58 +08:00
* Run `new mvc --help` to get help on this command.
2018-02-13 06:22:43 +08:00
---
Alternatively, you can create a new ASP.NET Core project with Visual Studio:
* In Visual Studio, create a new **Web Application** project.
* Select **ASP.NET Core 2.0** . ** .NET Core** is selected in the following image, but you can select ** .NET Framework**.
* Select **Change Authentication** and set to **Individual User Accounts** .
* Keep the default **Store user accounts in-app** .
![New Project dialog showing "Individual User Accounts radio" selected ](accconfirm/_static/2.png )
2017-07-25 01:41:58 +08:00
## Test new user registration
2018-02-13 06:22:43 +08:00
Run the app, select the **Register** link, and register a user. Follow the instructions to run Entity Framework Core migrations. At this point, the only validation on the email is with the [[EmailAddress]](/dotnet/api/system.componentmodel.dataannotations.emailaddressattribute) attribute. After submitting the registration, you are logged into the app. Later in the tutorial, the code is updated so new users can't log in until their email has been validated.
2016-10-29 01:35:15 +08:00
2017-03-09 03:49:26 +08:00
## View the Identity database
2016-10-29 01:35:15 +08:00
2018-03-22 08:18:35 +08:00
See [Work with SQLite in an ASP.NET Core MVC project ](xref:tutorials/first-mvc-app-xplat/working-with-sql ) for instructions on how to view the SQLite database.
2018-02-13 06:22:43 +08:00
For Visual Studio:
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
* From the **View** menu, select **SQL Server Object Explorer** (SSOX).
2017-07-25 01:41:58 +08:00
* Navigate to ** (localdb)MSSQLLocalDB(SQL Server 13)**. Right-click on **dbo.AspNetUsers** > **View Data** :
2016-10-29 01:35:15 +08:00
2016-12-23 02:03:29 +08:00
![Contextual menu on AspNetUsers table in SQL Server Object Explorer ](accconfirm/_static/ssox.png )
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Note the table's `EmailConfirmed` field is `False` .
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
You might want to use this email again in the next step when the app sends a confirmation email. Right-click on the row and select **Delete** . Deleting the email alias makes it easier in the following steps.
2017-07-25 01:41:58 +08:00
---
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
## Require HTTPS
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
See [Require HTTPS ](xref:security/enforcing-ssl ).
2016-10-29 01:35:15 +08:00
2017-07-25 01:41:58 +08:00
< a name = "prevent-login-at-registration" > < / a >
2016-10-29 01:35:15 +08:00
## Require email confirmation
2018-02-13 06:22:43 +08:00
It's a best practice to confirm the email of a new user registration. Email confirmation helps to verify they're not impersonating someone else (that is, they haven't registered with someone else's email). Suppose you had a discussion forum, and you wanted to prevent "yli@example.com" from registering as "nolivetto@contoso.com." Without email confirmation, "nolivetto@contoso.com" could receive unwanted email from your app. Suppose the user accidentally registered as "ylo@example.com" and hadn't noticed the misspelling of "yli". They wouldn't be able to use password recovery because the app doesn't have their correct email. Email confirmation provides only limited protection from bots. Email confirmation doesn't provide protection from malicious users with many email accounts.
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
You generally want to prevent new users from posting any data to your web site before they have a confirmed email.
2016-11-17 03:01:55 +08:00
Update `ConfigureServices` to require a confirmed email:
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebPWrecover/Startup.cs?name=snippet1&highlight=12-17 )]
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
`config.SignIn.RequireConfirmedEmail = true;` prevents registered users from logging in until their email is confirmed.
2017-07-25 01:41:58 +08:00
2016-10-29 01:35:15 +08:00
### Configure email provider
2018-02-12 02:36:03 +08:00
In this tutorial, SendGrid is used to send email. You need a SendGrid account and key to send email. You can use other email providers. ASP.NET Core 2.x includes `System.Net.Mail` , which allows you to send email from your app. We recommend you use SendGrid or another email service to send email. SMTP is difficult to secure and set up correctly.
2017-07-25 01:41:58 +08:00
2017-11-29 08:09:16 +08:00
The [Options pattern ](xref:fundamentals/configuration/options ) is used to access the user account and key settings. For more information, see [configuration ](xref:fundamentals/configuration/index ).
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Create a class to fetch the secure email key. For this sample, the `AuthMessageSenderOptions` class is created in the *Services/AuthMessageSenderOptions.cs* file:
2016-10-29 01:35:15 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebPWrecover/Services/AuthMessageSenderOptions.cs?name=snippet1 )]
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Set the `SendGridUser` and `SendGridKey` with the [secret-manager tool ](xref:security/app-secrets ). For example:
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
```console
2017-03-09 03:49:26 +08:00
C:\WebAppl\src\WebApp1>dotnet user-secrets set SendGridUser RickAndMSFT
2016-10-29 01:35:15 +08:00
info: Successfully saved SendGridUser = RickAndMSFT to the secret store.
2016-11-18 13:03:07 +08:00
```
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
On Windows, Secret Manager stores keys/value pairs in a *secrets.json* file in the `%APPDATA%/Microsoft/UserSecrets/<WebAppName-userSecretsId>` directory.
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
The contents of the *secrets.json* file aren't encrypted. The *secrets.json* file is shown below (the `SendGridKey` value has been removed.)
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
```json
2017-03-09 03:49:26 +08:00
{
"SendGridUser": "RickAndMSFT",
"SendGridKey": "< key removed > "
}
```
2016-10-29 01:35:15 +08:00
2017-07-25 01:41:58 +08:00
### Configure startup to use AuthMessageSenderOptions
2016-10-29 01:35:15 +08:00
Add `AuthMessageSenderOptions` to the service container at the end of the `ConfigureServices` method in the *Startup.cs* file:
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x/)
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebPWrecover/Startup.cs?name=snippet2&highlight=28 )]
2017-07-25 01:41:58 +08:00
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x/)
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebApp1/Startup.cs?name=snippet1&highlight=26 )]
2016-10-29 01:35:15 +08:00
2018-05-11 08:58:40 +08:00
---
2017-03-09 03:49:26 +08:00
### Configure the AuthMessageSender class
2016-10-29 01:35:15 +08:00
2017-07-25 01:41:58 +08:00
This tutorial shows how to add email notifications through [SendGrid ](https://sendgrid.com/ ), but you can send email using SMTP and other mechanisms.
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Install the `SendGrid` NuGet package:
* From the command line:
`dotnet add package SendGrid`
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
* From the Package Manager Console, enter the following command:
2016-10-29 01:35:15 +08:00
2018-04-05 07:51:35 +08:00
`Install-Package SendGrid`
2018-02-13 06:22:43 +08:00
See [Get Started with SendGrid for Free ](https://sendgrid.com/free/ ) to register for a free SendGrid account.
2017-07-25 01:41:58 +08:00
#### Configure SendGrid
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x/)
2018-02-13 06:22:43 +08:00
To configure SendGrid, add code similar to the following in *Services/EmailSender.cs* :
2017-07-25 01:41:58 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebPWrecover/Services/EmailSender.cs )]
2017-07-25 01:41:58 +08:00
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x/)
2017-03-09 03:49:26 +08:00
* Add code in *Services/MessageServices.cs* similar to the following to configure SendGrid:
2016-10-29 01:35:15 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebApp1/Services/MessageServices.cs )]
2016-10-29 01:35:15 +08:00
2018-05-11 08:58:40 +08:00
---
2016-10-29 01:35:15 +08:00
## Enable account confirmation and password recovery
2018-02-13 06:22:43 +08:00
The template has the code for account confirmation and password recovery. Find the `OnPostAsync` method in *Pages/Account/Register.cshtml.cs* .
2016-10-29 01:35:15 +08:00
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x/)
2017-07-25 01:41:58 +08:00
Prevent newly registered users from being automatically logged on by commenting out the following line:
2018-02-13 06:22:43 +08:00
```csharp
2017-07-25 01:41:58 +08:00
await _signInManager.SignInAsync(user, isPersistent: false);
```
The complete method is shown with the changed line highlighted:
2017-03-09 03:49:26 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebPWrecover/Pages/Account/Register.cshtml.cs?highlight=16&name=snippet_Register )]
2017-12-02 05:41:34 +08:00
2018-05-11 08:58:40 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x/)
2018-02-13 06:22:43 +08:00
To enable account confirmation, uncomment the following code:
2017-07-25 01:41:58 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebApp1/Controllers/AccountController.cs?highlight=16-25&name=snippet_Register )]
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
**Note:** The code is preventing a newly registered user from being automatically logged on by commenting out the following line:
2017-03-09 03:49:26 +08:00
2018-02-13 06:22:43 +08:00
```csharp
2017-03-09 03:49:26 +08:00
//await _signInManager.SignInAsync(user, isPersistent: false);
```
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Enable password recovery by uncommenting the code in the `ForgotPassword` action of *Controllers/AccountController.cs* :
2016-10-29 01:35:15 +08:00
2018-02-25 00:08:11 +08:00
[!code-csharp[ ](accconfirm/sample/WebApp1/Controllers/AccountController.cs?highlight=17-23&name=snippet_ForgotPassword )]
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Uncomment the form element in *Views/Account/ForgotPassword.cshtml* . You might want to remove the `<p> For more information on how to enable reset password ... </p>` element, which contains a link to this article.
2016-10-29 01:35:15 +08:00
2018-02-25 00:08:11 +08:00
[!code-cshtml[ ](accconfirm/sample/WebApp1/Views/Account/ForgotPassword.cshtml?highlight=7-10,12,28 )]
2016-10-29 01:35:15 +08:00
2018-05-11 08:58:40 +08:00
---
2016-10-29 01:35:15 +08:00
## Register, confirm email, and reset password
2017-07-25 01:41:58 +08:00
Run the web app, and test the account confirmation and password recovery flow.
2016-10-29 01:35:15 +08:00
2017-03-09 03:49:26 +08:00
* Run the app and register a new user
2016-10-29 01:35:15 +08:00
2018-04-05 07:51:35 +08:00
![Web application Account Register view ](accconfirm/_static/loginaccconfirm1.png )
2016-10-29 01:35:15 +08:00
2017-07-25 01:41:58 +08:00
* Check your email for the account confirmation link. See [Debug email ](#debug ) if you don't get the email.
2016-10-29 01:35:15 +08:00
* Click the link to confirm your email.
* Log in with your email and password.
* Log off.
2017-07-25 01:41:58 +08:00
### View the manage page
Select your user name in the browser:
![browser window with user name ](accconfirm/_static/un.png )
You might need to expand the navbar to see user name.
![navbar ](accconfirm/_static/x.png )
2017-08-18 04:20:27 +08:00
# [ASP.NET Core 2.x](#tab/aspnetcore2x)
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
The manage page is displayed with the **Profile** tab selected. The **Email** shows a check box indicating the email has been confirmed.
2017-07-25 01:41:58 +08:00
![manage page ](accconfirm/_static/rick2.png )
2017-08-18 04:20:27 +08:00
# [ASP.NET Core 1.x](#tab/aspnetcore1x)
2017-07-25 01:41:58 +08:00
2018-02-13 06:22:43 +08:00
This is mentioned later in the tutorial.
2017-07-25 01:41:58 +08:00
![manage page ](accconfirm/_static/rick2.png )
---
2016-10-29 01:35:15 +08:00
### Test password reset
2018-02-13 06:22:43 +08:00
* If you're logged in, select **Logout** .
2017-03-09 03:49:26 +08:00
* Select the **Log in** link and select the **Forgot your password?** link.
2016-10-29 01:35:15 +08:00
* Enter the email you used to register the account.
2018-02-13 06:22:43 +08:00
* An email with a link to reset your password is sent. Check your email and click the link to reset your password. After your password has been successfully reset, you can log in with your email and new password.
2016-10-29 01:35:15 +08:00
2017-06-19 23:49:17 +08:00
< a name = "debug" > < / a >
### Debug email
If you can't get email working:
2018-02-13 06:22:43 +08:00
* Create a [console app to send email ](https://sendgrid.com/docs/Integrate/Code_Examples/v2_Mail/csharp.html ).
2017-06-19 23:49:17 +08:00
* Review the [Email Activity ](https://sendgrid.com/docs/User_Guide/email_activity.html ) page.
2017-07-25 01:41:58 +08:00
* Check your spam folder.
* Try another email alias on a different email provider (Microsoft, Yahoo, Gmail, etc.)
2017-06-19 23:49:17 +08:00
* Try sending to different email accounts.
2018-02-13 06:22:43 +08:00
**A security best practice** is to **not** use production secrets in test and development. If you publish the app to Azure, you can set the SendGrid secrets as application settings in the Azure Web App portal. The configuration system is set up to read keys from environment variables.
2016-10-29 01:35:15 +08:00
## Combine social and local login accounts
2018-03-02 05:21:56 +08:00
To complete this section, you must first enable an external authentication provider. See [Facebook, Google, and external provider authentication ](xref:security/authentication/social/index ).
2016-10-29 01:35:15 +08:00
2017-07-25 01:41:58 +08:00
You can combine local and social accounts by clicking on your email link. In the following sequence, "RickAndMSFT@gmail.com" is first created as a local login; however, you can create the account as a social login first, then add a local login.
2016-10-29 01:35:15 +08:00
2016-12-23 02:03:29 +08:00
![Web application: RickAndMSFT@gmail.com user authenticated ](accconfirm/_static/rick.png )
2016-10-29 01:35:15 +08:00
Click on the **Manage** link. Note the 0 external (social logins) associated with this account.
2016-12-23 02:03:29 +08:00
![Manage view ](accconfirm/_static/manage.png )
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
Click the link to another login service and accept the app requests. In the following image, Facebook is the external authentication provider:
2016-10-29 01:35:15 +08:00
2016-12-23 02:03:29 +08:00
![Manage your external logins view listing Facebook ](accconfirm/_static/fb.png )
2016-10-29 01:35:15 +08:00
2018-02-13 06:22:43 +08:00
The two accounts have been combined. You are able to log on with either account. You might want your users to add local accounts in case their social login authentication service is down, or more likely they've lost access to their social account.
## Enable account confirmation after a site has users
Enabling account confirmation on a site with users locks out all the existing users. Existing users are locked out because their accounts aren't confirmed. To work around exiting user lockout, use one of the following approaches:
* Update the database to mark all existing users as being confirmed
* Confirm exiting users. For example, batch-send emails with confirmation links.