protected override void ApplyResponseChallenge()
        {
            if (ShouldConvertChallengeToForbidden())
            {
                // Handle 403 by redirecting to AccessDeniedPath if set
                if (Options.AccessDeniedPath.HasValue)
                {
                    try
                    {
                        var accessDeniedUri =
                            Request.Scheme +
                            "://" +
                            Request.Host +
                            Request.PathBase +
                            Options.AccessDeniedPath;

                        var redirectContext = new CookieApplyRedirectContext(Context, Options, accessDeniedUri);
                        Options.Notifications.ApplyRedirect(redirectContext);
                    }
                    catch (Exception exception)
                    {
                        var exceptionContext = new CookieExceptionContext(Context, Options,
                                                                          CookieExceptionContext.ExceptionLocation.ApplyResponseChallenge, exception, ticket: null);
                        Options.Notifications.Exception(exceptionContext);
                        if (exceptionContext.Rethrow)
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    Response.StatusCode = 403;
                }
                return;
            }

            if (Response.StatusCode != 401 || !Options.LoginPath.HasValue)
            {
                return;
            }

            // Automatic middleware should redirect on 401 even if there wasn't an explicit challenge.
            if (ChallengeContext == null && !Options.AutomaticAuthentication)
            {
                return;
            }

            string loginUri = string.Empty;

            if (ChallengeContext != null)
            {
                loginUri = new AuthenticationProperties(ChallengeContext.Properties).RedirectUri;
            }

            try
            {
                if (string.IsNullOrWhiteSpace(loginUri))
                {
                    string currentUri =
                        Request.PathBase +
                        Request.Path +
                        Request.QueryString;

                    loginUri =
                        Request.Scheme +
                        "://" +
                        Request.Host +
                        Request.PathBase +
                        Options.LoginPath +
                        new QueryString(Options.ReturnUrlParameter, currentUri);
                }

                var redirectContext = new CookieApplyRedirectContext(Context, Options, loginUri);
                Options.Notifications.ApplyRedirect(redirectContext);
            }
            catch (Exception exception)
            {
                CookieExceptionContext exceptionContext = new CookieExceptionContext(Context, Options,
                                                                                     CookieExceptionContext.ExceptionLocation.ApplyResponseChallenge, exception, ticket: null);
                Options.Notifications.Exception(exceptionContext);
                if (exceptionContext.Rethrow)
                {
                    throw;
                }
            }
        }
        protected override async Task ApplyResponseGrantAsync()
        {
            var  signin        = SignInContext;
            bool shouldSignin  = signin != null;
            var  signout       = SignOutContext;
            bool shouldSignout = signout != null;

            if (!(shouldSignin || shouldSignout || _shouldRenew))
            {
                return;
            }

            AuthenticationTicket model = await AuthenticateAsync();

            try
            {
                var cookieOptions = new CookieOptions
                {
                    Domain   = Options.CookieDomain,
                    HttpOnly = Options.CookieHttpOnly,
                    Path     = Options.CookiePath ?? (RequestPathBase.HasValue ? RequestPathBase.ToString() : "/"),
                };
                if (Options.CookieSecure == CookieSecureOption.SameAsRequest)
                {
                    cookieOptions.Secure = Request.IsHttps;
                }
                else
                {
                    cookieOptions.Secure = Options.CookieSecure == CookieSecureOption.Always;
                }

                if (shouldSignin)
                {
                    var signInContext = new CookieResponseSignInContext(
                        Context,
                        Options,
                        Options.AuthenticationScheme,
                        signin.Principal,
                        signin.Properties,
                        cookieOptions);

                    DateTimeOffset issuedUtc;
                    if (signin.Properties.IssuedUtc.HasValue)
                    {
                        issuedUtc = signin.Properties.IssuedUtc.Value;
                    }
                    else
                    {
                        issuedUtc = Options.SystemClock.UtcNow;
                        signin.Properties.IssuedUtc = issuedUtc;
                    }

                    if (!signin.Properties.ExpiresUtc.HasValue)
                    {
                        signin.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
                    }

                    Options.Notifications.ResponseSignIn(signInContext);

                    if (signInContext.Properties.IsPersistent)
                    {
                        DateTimeOffset expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
                        signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime;
                    }

                    model = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.AuthenticationScheme);
                    if (Options.SessionStore != null)
                    {
                        if (_sessionKey != null)
                        {
                            await Options.SessionStore.RemoveAsync(_sessionKey);
                        }
                        _sessionKey = await Options.SessionStore.StoreAsync(model);

                        var principal = new ClaimsPrincipal(
                            new ClaimsIdentity(
                                new[] { new Claim(SessionIdClaim, _sessionKey) },
                                Options.AuthenticationScheme));
                        model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
                    }
                    string cookieValue = Options.TicketDataFormat.Protect(model);

                    Options.CookieManager.AppendResponseCookie(
                        Context,
                        Options.CookieName,
                        cookieValue,
                        signInContext.CookieOptions);

                    var signedInContext = new CookieResponseSignedInContext(
                        Context,
                        Options,
                        Options.AuthenticationScheme,
                        signInContext.Principal,
                        signInContext.Properties);

                    Options.Notifications.ResponseSignedIn(signedInContext);
                }
                else if (shouldSignout)
                {
                    if (Options.SessionStore != null && _sessionKey != null)
                    {
                        await Options.SessionStore.RemoveAsync(_sessionKey);
                    }

                    var context = new CookieResponseSignOutContext(
                        Context,
                        Options,
                        cookieOptions);

                    Options.Notifications.ResponseSignOut(context);

                    Options.CookieManager.DeleteCookie(
                        Context,
                        Options.CookieName,
                        context.CookieOptions);
                }
                else if (_shouldRenew)
                {
                    model.Properties.IssuedUtc  = _renewIssuedUtc;
                    model.Properties.ExpiresUtc = _renewExpiresUtc;

                    if (Options.SessionStore != null && _sessionKey != null)
                    {
                        await Options.SessionStore.RenewAsync(_sessionKey, model);

                        var principal = new ClaimsPrincipal(
                            new ClaimsIdentity(
                                new[] { new Claim(SessionIdClaim, _sessionKey) },
                                Options.AuthenticationScheme));
                        model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
                    }

                    string cookieValue = Options.TicketDataFormat.Protect(model);

                    if (model.Properties.IsPersistent)
                    {
                        cookieOptions.Expires = _renewExpiresUtc.ToUniversalTime().DateTime;
                    }

                    Options.CookieManager.AppendResponseCookie(
                        Context,
                        Options.CookieName,
                        cookieValue,
                        cookieOptions);
                }

                Response.Headers.Set(
                    HeaderNameCacheControl,
                    HeaderValueNoCache);

                Response.Headers.Set(
                    HeaderNamePragma,
                    HeaderValueNoCache);

                Response.Headers.Set(
                    HeaderNameExpires,
                    HeaderValueMinusOne);

                bool shouldLoginRedirect  = shouldSignin && Options.LoginPath.HasValue && Request.Path == Options.LoginPath;
                bool shouldLogoutRedirect = shouldSignout && Options.LogoutPath.HasValue && Request.Path == Options.LogoutPath;

                if ((shouldLoginRedirect || shouldLogoutRedirect) && Response.StatusCode == 200)
                {
                    IReadableStringCollection query = Request.Query;
                    string redirectUri = query.Get(Options.ReturnUrlParameter);
                    if (!string.IsNullOrWhiteSpace(redirectUri) &&
                        IsHostRelative(redirectUri))
                    {
                        var redirectContext = new CookieApplyRedirectContext(Context, Options, redirectUri);
                        Options.Notifications.ApplyRedirect(redirectContext);
                    }
                }
            }
            catch (Exception exception)
            {
                CookieExceptionContext exceptionContext = new CookieExceptionContext(Context, Options,
                                                                                     CookieExceptionContext.ExceptionLocation.ApplyResponseGrant, exception, model);
                Options.Notifications.Exception(exceptionContext);
                if (exceptionContext.Rethrow)
                {
                    throw;
                }
            }
        }