19

I'm generating a usertoken like so

public async Task GenerateCode()
{

    var code = await UserManager.GenerateUserTokenAsync("heymega", new Guid("16139fcd-7ae0-449c-ad1c-f568bbe46744"));


}

I then pass the same token into another action via a separate request

public async Task ValidateCode(string code)
{

    var valid = await UserManager.VerifyUserTokenAsync(new Guid("16139fcd-7ae0-449c-ad1c-f568bbe46744"), "heymega", code); //Returns False

}

However, the response from the VerifyUserTokenAsync method is always false.

If I were to generate the code and verify within the same action

public async Task GenerateCode()
{

    var code = await UserManager.GenerateUserTokenAsync("heymega", new Guid("16139fcd-7ae0-449c-ad1c-f568bbe46744"));

    var valid = await UserManager.VerifyUserTokenAsync(new Guid("16139fcd-7ae0-449c-ad1c-f568bbe46744"), "heymega", code); //Returns True

}

It returns true.

Why can't the Verify method verify the code in a separate request? Am I missing something obvious?

heymega
  • 9,215
  • 8
  • 42
  • 61

6 Answers6

24

I finally figured this after pulling my hair out for hours. You need to URL encode the code and I decided to use the HttpUtility class for this.

HttpUtility.UrlEncode(code);

When it comes to verifying the code, you do not need to URL decode the code.

heymega
  • 9,215
  • 8
  • 42
  • 61
  • 1
    It took me too long to find this answer...but when I did it solved my issue! Thanks. – Cos Callis Aug 18 '16 at 13:07
  • 5
    I'm not sure what version of ASP.NET Identity you have installed. But I am using version 2.2.1 and I absolutely have to use HttpUtility.UrlDecode(code) when I verify the code. Otherwise, it ALWAYS returns false. – brsfan Apr 12 '17 at 23:15
  • If you have to use UrlDecode explicitly to verify the code then you probably double-encoded it when you created your URL. It shouldn't be necessary. – Simon_Weaver Apr 27 '19 at 00:06
  • Using UrlDecode on the token did not work for me. I have not to decode the token – Tristan Djahel May 21 '19 at 12:59
  • I'd like to add that VerifyUserToken can certainly handle URL decoded tokens, so if you are seeing it return false I don't see how this could be the answer. – Josh Dec 05 '19 at 20:22
  • 1
    +1 to most likely needing to use `HttpUtility.UrlDecode` before passing the token to `VerifyUserTokenAsync`. At least I seem to need it. – Jedidja Nov 13 '20 at 12:03
3

Having just burned 2 days on this issue, here is another reason this might be happening to you.

In your Startup.cs - ConfigureServices(IServiceCollection services) method, ensure that:

services.AddAuthentication

Appears BEFORE

services.AddIdentity

Otherwise calls to VerifyUserTokenAsync will always return false

pieperu
  • 2,662
  • 3
  • 18
  • 31
0

Cannot solve this problem until haven't used this:

 UserManager.VerifyUserTokenAsync(userId, AccountLockedOutPurpose, code).WithCurrentCulture<bool>();

.WithCurrentCulture() - used in all methods such as ResetPasswordAsync etc.)

SirCapy
  • 295
  • 1
  • 12
0

In my situation I was instantiating a UserManager on demand when one was needed, as opposed to generating one per Owin context in my startup pipeline. Behavior wise, if I validated the token with the same instance of UserManager that created it, it would return true. But if I did an actual forgot password flow where the validation is in a separate request, it was always false.

Switching my setup so that a UserManager was created per owin context resolved the issue for me. Apparently there is some dependency on Owin when it comes to validating tokens.

            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Josh
  • 1,648
  • 8
  • 27
  • 58
0

Not sure if OP is using .Net Core or not, but if someone comes across this and you're using dependency injection, the solution for me was to scope the UserManager as a singleton.

services.AddSingleton<UserManager<YourUserAccountModel>>();

I believe this is because when the user clicks the confirm email link in their inbox, a new UserManager instance is injected to the controller and does not have the same key that was used to generate the token to begin with. Therefore it cannot verify the token.

slasky
  • 2,726
  • 4
  • 27
  • 36
0

For me, I got the same issue. and the solution was very simple.

In my case, I add the purpose with white space like this "Email Confirmation". the problem was solved when I removed any white space "EmailConfirmation".

bool IsTokenValed = await userManager.VerifyUserTokenAsync(user, userManager.Options.Tokens.EmailConfirmationTokenProvider, "EmailConfirmation", token);
MedoofromEgypt
  • 105
  • 1
  • 8