ASP.NET Core Identity Exception for "Identity.External"
First off, I’d avoid extending ServiceCollection class. Instead, I would call AddIdetityCore method. Check source code here.
Then:
services.AddIdentityCore<ApplicationUser>()
.AddUserStore<UserStore>()
.AddDefaultTokenProviders()
.AddSignInManager<SignInManager<ApplicationUser>>();
Second, you set up Events property in AddCookie method options. Since you didn’t set up a period of time for the ValidationInterval property, it will last exactly 30 minutes. This means that SecurityStamp property of the user will be verified in the next request the server does, once the time has come to an end. Since in the description you made you didn’t say if you have changed the password, I suspect that user’s SecurityStamp is null in BD while the Cookie version of it is an empty string, so when Identity does the validation between both versions (null == "") it will be false and then Identity would try to close the session of the Application Scheme, the Extern one and also the TwoFactor. Then it will throw the exception because only the ApplicationScheme is registered:
public virtual async Task SignOutAsync()
{
await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
await Context.SignOutAsync(IdentityConstants.ExternalScheme); //<- Problem and...
await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme); //... another problem.
}
The solution is first, making sure that SecurityStamp isn’t null. And then you have two options:
Adding the cookies for every scheme
Or
Override SignOutAsync method from SignInManager class.
public class SignInManager<TUser> : Microsoft.AspNetCore.Identity.SignInManager<TUser>
where TUser : class
{
public SignInManager(
UserManager<TUser> userManager,
IHttpContextAccessor contextAccessor,
IUserClaimsPrincipalFactory<TUser> claimsFactory,
IOptions<IdentityOptions> optionsAccessor,
ILogger<Microsoft.AspNetCore.Identity.SignInManager<TUser>> logger,
IAuthenticationSchemeProvider schemes)
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
{
}
public async override Task SignOutAsync()
{
await Context.SignOutAsync(IdentityConstants.ApplicationScheme); // <-
}
}
Then:
services.AddIdentityCore<ApplicationUser>()
.AddUserStore<UserStore>()
.AddDefaultTokenProviders()
.AddSignInManager<Services.Infrastructure.Identity.SignInManager<ApplicationUser>>() //<-