6

I am trying to implement a way for users to change their email in AspNetCore so on the Account Management screen I have the change function that will call GenerateChangeEmailTokenAsync on the user manager, then sends the email with the link containing the Token and UserId.

My problem is how do I allow the link the change the email address to the new address since ChangeEmailAsync requires the new email address be entered.

What is the best practice way of implementing this functionality? I do not want to send over the new email address in the email link but also do not want to make them type the email again. Hopefully someone has done this, I cannot find it anywhere only, and it should be very simple.

Tim Scriv
  • 670
  • 7
  • 17

2 Answers2

17

I know it is late answering this, but I was looking for it myself before, and thought I leave the answer here for others.

The GenerateChangeEmailTokenAsync method takes the new email as part in the hash of the token. Next you create a link that contains the token, the new email and the old email

 var token = await _userManager.GenerateChangeEmailTokenAsync(user, model.NewEmail);
 var resetLink = Url.Action("ChangeEmailToken", "account", new {token = token, oldEmail = user.Email, newEmail = model.newEmail }, protocol: HttpContext.Request.Scheme);

Next you send this link to the user in an email.

When clicked, the user hits the method named in the link (here "ChangeEmailToken" on AccountController:

 [AllowAnonymous]
 [HttpGet]
 public async Task<IActionResult> ChangeEmailToken([FromQuery] string token, [FromQuery] string oldEmail, [FromQuery] string newEmail)

Next you need to verify the token, and -if succesful- update the email address.

var result = await _userManager.ChangeEmailAsync(user, newEmail, token);
Pieter van Kampen
  • 1,957
  • 17
  • 21
3

The normal flow is to let the user update profile as usual.

If the user updated their email address then that new email address needs to be verified.

That is when you generate the token with GenerateChangeEmailTokenAsync.

You send that token as a link to the new email address.

When the user clicks the link in the new email it takes them back to you site which automatically confirms the token and verifies the new email address.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    Yes that is what I got but the part that I am missing it how does it verify the new email address. The new address is not stored anywhere so when they click the link with the token the application has no idea what is the new address. How should I get that email address? – Tim Scriv Apr 02 '16 at 14:57
  • the accounts should have an email field/column. that's where you would have stored the email address when they registered/created the account. then as i described above. if they update their account and the email address has changed then you go through the email confirmation process – Nkosi Apr 02 '16 at 16:37
  • The email column does not change until after they have clicked the link in their email. This ensures that they are not stranded out of their account while waiting to confirm a new email. This also means that the new email is not stored anywhere in the DB. I think the best way might be to add a new column for unconfirmed email. And then pull that when they click the link. – Tim Scriv Apr 03 '16 at 14:25
  • There is normally an `EmailConfirmed` boolean column for that very purpose. – Nkosi Apr 03 '16 at 14:28
  • True. I was thinking about that but the GenerateChangeEmail token does not change the email address but the Confirm does change it. Plus if they change their email address and it has a not confirmed email then they will not be able to log in or recieve alerts until they confirm again(could be awhile). So I need a way that continues to allow the user to use his/her old email until they have confirmed the new one. – Tim Scriv Apr 03 '16 at 15:16
  • lockout till confirmation is by design. if they are using email to log in then when editing their their profile user is warned that by changing their email, which is used for authentication, that they will not be allowed to continue using account till they have re-confirm they new email address – Nkosi Apr 03 '16 at 15:18
  • I also thought about that so I tried following the flow for Twitter. They continue to allow for the previously confirmed email until you confirm the new one. If the user has confirmed an email address then they should be able to use that until they confirm a new one. Also it is clearly not the design because the GenerateChangeEmailToken does not change the email but AFTER they have clicked the link it changes the email address. – Tim Scriv Apr 03 '16 at 15:28
  • Point taken. take a look at the source on GitHub https://github.com/aspnet/Identity/blob/9010dd4284a10d7812ffc6bb6dd9542bd5b13249/src/Microsoft.AspNetCore.Identity/UserManager.cs#L1377 Seeing that then i suggest you store the email somewhere along with the token and userid/name. and only email the token. when the token returns to the server via click you then lookup the needed information to change the email and use them – Nkosi Apr 03 '16 at 15:48
  • It's OK. There is some good information that will probably help other situations. I think I might just add a temporary claim to the user for unconfirmed email. Should work well. Thank you! – Tim Scriv Apr 03 '16 at 16:57