heymega
heymega

Reputation: 9391

UserManager VerifyUserTokenAsync Always False

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?

Upvotes: 21

Views: 12130

Answers (6)

MedoofromEgypt
MedoofromEgypt

Reputation: 105

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);

Upvotes: 0

slasky
slasky

Reputation: 3076

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.

Upvotes: 0

Josh
Josh

Reputation: 1610

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);

Upvotes: 0

pieperu
pieperu

Reputation: 2762

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

Upvotes: 3

SirCapy
SirCapy

Reputation: 295

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.)

Upvotes: 0

heymega
heymega

Reputation: 9391

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.

Upvotes: 27

Related Questions