public async Task <IActionResult> AdditionalAuthenticationFactor( AdditionalAuthenticationFactorViewModel model) { // check if we are in the context of an authorization request var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl); if (ModelState.IsValid) { // read identity from the temporary cookie var result = await HttpContext.AuthenticateAsync("idsrv.mfa"); if (result?.Succeeded != true) { throw new Exception("MFA authentication error"); } var subject = result.Principal.FindFirst(JwtClaimTypes.Subject)?.Value; var user = await _localUserService.GetUserBySubjectAsync(subject); var userSecret = await _localUserService.GetUserSecret(subject, "TOTP"); var authenticator = new TwoStepsAuthenticator.TimeAuthenticator(); if (!authenticator.CheckCode(userSecret.Secret, model.Totp, user)) { ModelState.AddModelError("totp", "TOTP is invalid."); return(View(model)); } await _events.RaiseAsync( new UserLoginSuccessEvent( user.Username, user.Subject, user.Username, clientId : context?.Client.ClientId)); // only set explicit expiration here if user chooses "remember me". // otherwise we rely upon expiration configured in cookie middleware. AuthenticationProperties props = null; if (AccountOptions.AllowRememberLogin && model.RememberLogin) { props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration) }; } ; // delete temporary cookie used during mfa await HttpContext.SignOutAsync("idsrv.mfa"); // issue authentication cookie with subject ID and username var isuser = new IdentityServerUser(user.Subject) { DisplayName = user.Username }; await HttpContext.SignInAsync(isuser, props); if (context != null) { if (context.IsNativeClient()) { // The client is native, so this change in how to // return the response is for better UX for the end user. return(this.LoadingPage("Redirect", model.ReturnUrl)); } // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null return(Redirect(model.ReturnUrl)); } // request for a local page if (Url.IsLocalUrl(model.ReturnUrl)) { return(Redirect(model.ReturnUrl)); } else if (string.IsNullOrEmpty(model.ReturnUrl)) { return(Redirect("~/")); } else { // user might have clicked on a malicious link - should be logged throw new Exception("invalid return URL"); } } return(View(model)); }