20

I have recently migrated Asp.net identity 1.0 to 2.0 . I am trying to verify email verification code using below method. But i am getting "Invalid Token" error message.

public async Task<HttpResponseMessage> ConfirmEmail(string userName, string code)
        {
            ApplicationUser user = UserManager.FindByName(userName);
            var result = await UserManager.ConfirmEmailAsync(user.Id, code);
            return Request.CreateResponse(HttpStatusCode.OK, result);
        }

Generating Email verification token using below code (And if i call ConfirmEmailAsyc immediate after generating token, which is working fine). But when i am calling using different method which is giving error

public async Task<HttpResponseMessage> GetEmailConfirmationCode(string userName)
        {
            ApplicationUser user = UserManager.FindByName(userName);
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
            //var result = await UserManager.ConfirmEmailAsync(user.Id, code);
            return Request.CreateResponse(HttpStatusCode.OK, code);
        }

Please help

5
  • Did you ever find the answer to this? I have been working on this all day, and it's does appear to work at all. Commented Aug 11, 2014 at 21:47
  • 3
    Hi, Its working now.. Its because of my oversight. After url encode and decode of verification tokens it working. Because I had some plus(+) symbols inside token Commented Aug 13, 2014 at 13:55
  • Kumar , can you please share what you did to solve it ? Commented Aug 18, 2014 at 17:51
  • 1
    @PitDigger - A simple fix is to use the Replace(" ","+"); Commented Sep 2, 2014 at 12:50
  • 1
    In my case (Asp.Net Core 3.0) it seems that the scaffolded pages introduced this error. See my answer here. Commented Oct 27, 2019 at 17:05

7 Answers 7

36

I found you had to encode the token before putting it into an email, but not when checking it afterwards. So my code to send the email reads:

                // Send an email with this link 
                string code = UserManager.GenerateEmailConfirmationToken(user.Id);

                // added HTML encoding
                string codeHtmlVersion = HttpUtility.UrlEncode(code);

                // for some weird reason the following commented out line (which should return an absolute URL) returns null instead
                // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);

                string callbackUrl = "(your URL)/Account/ConfirmEmail?userId=" +
                    user.Id + "&code=" + codeHtmlVersion;

                // Send an email with this link using class (not shown here)
                var m = new Email();

                m.ToAddresses.Add(user.Email);
                m.Subject = "Confirm email address for new account";

                m.Body =
                    "Hi " + user.UserName + dcr +
                    "You have been sent this email because you created an account on our website.  " +
                    "Please click on <a href =\"" + callbackUrl + "\">this link</a> to confirm your email address is correct. ";

The code confirming the email then reads:

// user has clicked on link to confirm email
    [AllowAnonymous]
    public async Task<ActionResult> ConfirmEmail(string userId, string code)
    {

        // email confirmation page            
        // don't HTTP decode

        // try to authenticate
        if (userId == null || code == null)
        {
            // report an error somehow
        }
        else
        {

            // check if token OK
            var result = UserManager.ConfirmEmail(userId, code);
            if (result.Succeeded)
            {
                // report success
            }
            else
            {
                // report failure
            }
        }

Worked in the end for me!

Sign up to request clarification or add additional context in comments.

1 Comment

HttpUtility.UrlEncode fixed the problem at my end. Thanks a lot!
6

Hi this happened if I am getting the url(full) and calling to the api throught WebClient. The code value have to be Encoded before sending the call.

code = HttpUtility.UrlEncode(code); 

Comments

3

Hope the issue got resolved. Otherwise below is the link for the solution which worked well.

Asp.NET - Identity 2 - Invalid Token Error

Simply use:

emailConfirmationCode = await 
UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
UserManager.ConfirmEmailAsync(userId, code1);

Comments

3

My issue was slightly different.

I created my own IUserStore and one thing I was doing wrong was setting the SecurityStamp to null if there was no value.

The security stamp is used to generate the token but it's replaced by an empty string when the token is generated, however it is not replaced when validating the token, so it ends up comparing String.Empty to null, which will always return false.

I fixed my issue by replacing null values for String.Empty when reading from the database.

1 Comment

If you try both to verify PhoneNumber and Email then this InvalidToken could happen due to SecurityStamp being altered when calling ChangePhoneNumberAsync() to verity PhoneNumber. Some more insights about this topic if this is your problem: stackoverflow.com/questions/36182915/…
3

Had the same issue. The fix was to HTML encode the token when generating the link, and when confirming - HTML decode it back.

    public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null )
            {
                // Don't reveal that the user does not exist or is not confirmed
                return RedirectToAction(nameof(ForgotPasswordConfirmation));
            }

            var code = await _userManager.GeneratePasswordResetTokenAsync( user );

            var codeHtmlVersion = HttpUtility.UrlEncode( code );
            var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, codeHtmlVersion, Request.Scheme);
            await _emailSender.SendEmailAsync(
                model.Email, 

                $"You can reset your password by clicking here: <a href='{callbackUrl}'>link</a>", 
                _logger );
            return RedirectToAction(nameof(ForgotPasswordConfirmation));
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user == null)
        {
            // Don't reveal that the user does not exist
            return RedirectToAction(nameof(ResetPasswordConfirmation));
        }

        var codeHtmlDecoded = HttpUtility.UrlDecode( model.Code );

        var result = await _userManager.ResetPasswordAsync(user, codeHtmlDecoded, model.Password);
        if (result.Succeeded)
        {
            return RedirectToAction(nameof(ResetPasswordConfirmation));
        }
        AddErrors(result);
        return View();
    }

1 Comment

The concept here was what I needed to get stuff working, just don't do what I did: I was already encoding the token using AspNetCore.WebUtilities.WebEncoders for the Email link, but then I was trying to use HttpUtility (from the code above) to do the Decoding in the response to clicking the link. If you encode with WebUtilities.WebEncoders, be sure to Decode with WebUtilities.WebEncoders as well! see @walter33's Encode/Decode here: stackoverflow.com/questions/25405307/…
2

We had the same issue, Load balancing was causing this problem. Adding a <machineKey validationKey="XXX" decryptionKey="XXX" validation="SHA1" decryption="AES"/> in web.config file solved the problem. All your servers need to have the same machine key to verify previously generated code.

Hope this helps.

4 Comments

Adding what in web.config? The answer is incomplete.
Hi @MariuszIgnatowicz, Code tag did not show the config and I fixed it for you.
Will this work for ASP.NET Core 2.0 ? There is no Web.Config file in ASP.NET Core 2.0.
Please see the answer here stackoverflow.com/questions/46668192/…
-1

In my case, the HttpUtility.UrlEncode converted all plus signs (+) to empty spaces (" ") so the token was indeed invalid when it was passed back.

To resolve the issue, I simply replaced all characters + to %2b before the encode: HttpUtility.UrlEncode(code.Replace("+", "%2b"))

var code = await _userManager.GenerateEmailConfirmationTokenAsync(applicationUser);
string codeHtmlVersion = HttpUtility.UrlEncode(code.Replace("+", "%2b"));
var url = $"{baseUrl}/auth/verify/{applicationUser.Id}/{codeHtmlVersion}";

It is important that you decode before sending to ConfirmEmailAsync

var decodedCode = HttpUtility.UrlDecode(code);
var result = await _userManager.ConfirmEmailAsync(applicationUser, decodedCode);

This solved it for me

1 Comment

HttpUtility.UrlEncode converted all plus signs (+) to empty spaces (" ") this is wrong, UrlEncode replaces "+" to "%2b". If you use + with UrlDecode, it will be replaced into whitespace character. See dotnetfiddle.net/6etXc0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.