user2058413
user2058413

Reputation: 805

Asp.net core Identity Password reset "invalid token" even though tokens generated are identical

I am on Asp.Net core with .Net 5.0 In startup I have added;

        services.AddIdentity<ApplicationUser, ApplicationRole>(SetupIdentityOptions)
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        
        services.Configure<DataProtectionTokenProviderOptions>(opt => 
            {
                opt.TokenLifespan = TimeSpan.FromDays(1);
            }
        );

I generate the code as below(encoding done as per the MS docs);

            var code = await CommonServices.UserManager.GeneratePasswordResetTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

            var callbackUrl = $"{request.RequestData.ReturnUrl}?code={code}";

Now if I save the code generated at this point and check the code received to controller after user clicks the link they are identical. However when I do;

var result = await CS.UserManager.ResetPasswordAsync(user, model.Code, model.Password);

it gives me "Invalid Token" however tokens are identical.

Then I tried this and still says invalid token;

var isValidToken = await _userManager.VerifyUserTokenAsync(
user,
_userManager.Options.Tokens.PasswordResetTokenProvider,
UserManager<TUser>.ResetPasswordTokenPurpose,
code);

I am not sure whether the Identity framework saves the generated tokens in [AspNetUserTokens] table. I can't find any saved tokens after a generating the token.

What may be the problem?

Upvotes: 3

Views: 1463

Answers (2)

Sameer Tanveer
Sameer Tanveer

Reputation: 11

I encountered the issue while configuring MFA during first login, where I offered users the choice of authentication methods: Email, SMS, or Authenticator App. The issue occurred only when the Authenticator App was selected.

After investigation, we found that configuring the Authenticator App resets the SecurityStamp for the user in the AspNetUsers table. So, any tokens generated before this reset are rendered invalid.

To resolve the issue, we adjusted our flow as follows:

Check if the Authenticator App is configured: Before proceeding with actions like password reset, confirm whether the user has completed MFA setup with the Authenticator App.

Generate a new token: After the Authenticator App is set up, create a fresh token and validate the user with this token.

Upvotes: 0

user2058413
user2058413

Reputation: 805

My bad, I had to convert the encoded string back which I haven't done.

So, since I used

code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

After user clicks the link, I have to;

var bytes = WebEncoders.Base64UrlDecode(model.Code);
var code = Encoding.UTF8.GetString(bytes);

and then call

ResetPasswordAsync(user, code, model.Password);

which worked

Upvotes: 3

Related Questions