Reputation: 3649
After signing in using two-factor with authenticator app, I set rememberClient to true like this:
await _signInManager.TwoFactorAuthenticatorSignInAsync(code: request.Code,
isPersistent: request.IsPersistent,
rememberClient: request.RememberClient);
Signing in works fine and I get the .AspNetCore.Identity.Application
and Identity.TwoFactorRememberMe
cookies. If I sign out and in again I don't need to use two-factor. So long everything is fine.
The problem is when I do some changes in the user, like the phone number, and the SecurityStamp is changed. After the change is made I use await _signInManager.RefreshSignInAsync(user)
. But the Identity.TwoFactorRememberMe
cookie isn't updated. This results in two problems:
await _signInManager.IsTwoFactorClientRememberedAsync(user)
, it will result in an error "Failed to validate a security stamp" and the .AspNetCore.Identity.Application
will be removed.I've tried to renew the Identity.TwoFactorRememberMe
cookie at the same time as the .AspNetCore.Identity.Application
cookie, like this:
await base.RefreshSignInAsync(user);
await RememberTwoFactorClientAsync(user);
It works, but it will also set the Identity.TwoFactorRememberMe
cookie for those who didn't have it before. I can't check if it is set before, because then I get the error I described in (2) above.
The next thing I will try is to do something like this for every place I do something which changes the user SecurityStamp:
var isTwoFactorClientRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user);
// do the changes...
await _signInManager.RefreshSignInAsync(user);
if (isTwoFactorClientRememberedAsync)
await _signInManager.RememberTwoFactorClientAsync(user);
Is there something I'm missing here, or is this the only way to go?
I'm using IdentityServer4 and a SPA app, but I don't believe that has anything to do with the problem.
Upvotes: 3
Views: 1267
Reputation: 3649
I ended up adding a method in my custom ApplicationSignInManager:
public async Task<TResult> KeepSignInAsync<TResult>(ApplicationUser user, Func<Task<TResult>> func)
{
var isTwoFactorClientRemembered = await IsTwoFactorClientRememberedAsync(user);
var result = await func();
await RefreshSignInAsync(user);
if (isTwoFactorClientRemembered)
await RememberTwoFactorClientAsync(user);
return result;
}
When I change something which will update the user SecurityStamp I use it like this:
var result = await _signInManager.KeepSignInAsync(user, () => _userManager.SetPhoneNumberAsync(user, phoneNumber));
Upvotes: 2