Quantcast
Channel: Security
Viewing all articles
Browse latest Browse all 4737

ASP.net Identity v2.0.0 Email Confirmation/Reset Password Errors

$
0
0

We just launched our web app 6 days ago and have had over 5000 people register for accounts, great!

The issue is 3-5% of those users who click the confirmation email link (and same seems to go for reset password) get shown the error screen presumably because they have an invalid token. 

I read on StackOverflow that you need to encode the url to avoid special characters throwing it off and then decode it right before you validate it. I did that to no effect though, some users were still getting errors on their validation token.

I also read that having different MachineKey's could be a reason tokens aren't processed as being valid. Everything is hosted on Azure so I presumed (and saw on SO) it was or should taken care of

So with 30-50 people emailing us for the past 6 days now about issues, I got desperate while I tried to come up wit a solution and set my confirmEmail action to be the following:

[AllowAnonymous]
        public ActionResult ConfirmEmail(string userId = null, string code = null)
        {
            if (userId == null || code == null)
            {
                return View("Error");
            }
            else
            {
                var emailCode = UserManager.GenerateEmailConfirmationToken(userId);
                var result = UserManager.ConfirmEmail(userId, emailCode);
                return View(result.Succeeded ? "ConfirmEmail" : "Error");
            }   
        }


I thought to myself there is no way in heck this could fail, it literally just generates a token and then immediately uses it - yet somehow it still fails (by fails I mean the user sees the error page)

My best guess as to a possible solution so far is this answer from SO (http://stackoverflow.com/questions/25405307/asp-net-identity-2-invalid-token-error, halfway down)

Every time when a UserManager is created (or new-ed), a new dataProtectionProvider is generated as well. So when a user receives the email and clicks the link the AccountController is already not the old one, neither are the _userManager and it's token provider. So the new token provider will fail because it has no that token in it's memory. Thus we need to use a single instance for the token provider.

Is that really the issue? If so, what the heck ASP.net Identity team? Why? 

Some of the things I have changed:

The default Register Action recommends sending confirmation emails the following way:

var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);

Where I have the following in my Register Action

string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your XXXXXXX account");

And then I specify the following in the SendEmailConfirmationTokenAsync

private async Task<string> SendEmailConfirmationTokenAsync(string userID, string subject)
        {
            string code = await UserManager.GenerateEmailConfirmationTokenAsync(userID);
            var callbackUrl = Url.Action("ConfirmEmail", "Account",
               new { userId = userID, code = code }, protocol: Request.Url.Scheme);

		// construct nice looking email body

    		await UserManager.SendEmailAsync(userID, subject, htmlBody);

            	return callbackUrl;
	}

To me, both sections are equivalent, is this not the case?

And then the only other thing I can think of is how I added my db class, but that shouldn't affect the UserManager should it?

The top part of my account controller looks like the following:

private SiteClasses db = new SiteClasses();

        public AccountController()
        {
        }

        public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
        {
            UserManager = userManager;
            SignInManager = signInManager;
        }

        private ApplicationUserManager _userManager;
        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }

	...

We are using the recommended email provider sendgrid and I have never been able to replicate this issue (after creating ~60 test accounts manaually) and most people seem to get along fine.

Part of this could be errors resulting from the users themselves, but this seems to be happening for a bunch of non tech-savvy people who just click on the link and expect it to work like a normal confirmation email should. Most users are coming to us from their iPhone where I would presume they are just using Apple's default mail client but not positive. I don't know of any spam filter or email settings that would remove the query string values from links.

I'm getting somewhat desperate for answers as I am trying to launch a great new startup but am getting hung up by ASP.net Identity technicalities or bugs or whatever is going on.


Viewing all articles
Browse latest Browse all 4737

Trending Articles