private async Task <bool> SendAuthorizationResponseAsync(OpenIdConnectResponse response, AuthenticationTicket ticket = null)
        {
            var request = Context.GetOpenIdConnectRequest();

            Context.SetOpenIdConnectResponse(response);

            response.SetProperty(OpenIdConnectConstants.Properties.MessageType,
                                 OpenIdConnectConstants.MessageTypes.AuthorizationResponse);

            // Note: as this stage, the request may be null (e.g if it couldn't be extracted from the HTTP request).
            var notification = new ApplyAuthorizationResponseContext(Context, Scheme, Options, ticket, request, response)
            {
                RedirectUri  = request?.GetProperty <string>(OpenIdConnectConstants.Properties.ValidatedRedirectUri),
                ResponseMode = request?.ResponseMode
            };

            // If the response_mode parameter was not specified, try to infer it.
            if (string.IsNullOrEmpty(notification.ResponseMode) && !string.IsNullOrEmpty(notification.RedirectUri))
            {
                notification.ResponseMode =
                    request.IsFormPostResponseMode() ? OpenIdConnectConstants.ResponseModes.FormPost :
                    request.IsFragmentResponseMode() ? OpenIdConnectConstants.ResponseModes.Fragment :
                    request.IsQueryResponseMode()    ? OpenIdConnectConstants.ResponseModes.Query    : null;
            }

            await Provider.ApplyAuthorizationResponse(notification);


            if (notification.Result != null)
            {
                if (notification.Result.Handled)
                {
                    Logger.LogDebug("The authorization request was handled in user code.");

                    return(true);
                }

                else if (notification.Result.Skipped)
                {
                    Logger.LogDebug("The default authorization request handling was skipped from user code.");

                    return(false);
                }
            }

            // Directly display an error page if redirect_uri cannot be used to
            // redirect the user agent back to the client application.
            if (!string.IsNullOrEmpty(response.Error) && string.IsNullOrEmpty(notification.RedirectUri))
            {
                // Apply a 400 status code by default.
                Response.StatusCode = 400;

                if (Options.ApplicationCanDisplayErrors)
                {
                    // Return false to allow the rest of
                    // the pipeline to handle the request.
                    return(false);
                }

                Logger.LogInformation("The authorization response was successfully returned " +
                                      "as a plain-text document: {Response}.", response);

                return(await SendNativePageAsync(response));
            }

            // At this stage, throw an exception if the request was not properly extracted.
            if (request == null)
            {
                throw new InvalidOperationException("The authorization response cannot be returned.");
            }

            // Attach the request state to the authorization response.
            if (string.IsNullOrEmpty(response.State))
            {
                response.State = request.State;
            }

            // Note: a dictionary is deliberately not used here to allow multiple parameters with the
            // same name to be specified. While initially not allowed by the core OAuth2 specification,
            // this is now accepted by derived drafts like the OAuth2 token exchange specification.
            // For consistency, multiple parameters with the same name are also supported by this endpoint.
            var parameters = new List <KeyValuePair <string, string> >();

            foreach (var parameter in response.GetParameters())
            {
                var values = (string[])parameter.Value;
                if (values == null)
                {
                    continue;
                }

                foreach (var value in values)
                {
                    parameters.Add(new KeyValuePair <string, string>(parameter.Key, value));
                }
            }

            // Note: at this stage, the redirect_uri parameter MUST be trusted.
            switch (notification.ResponseMode)
            {
            case OpenIdConnectConstants.ResponseModes.FormPost:
            {
                Logger.LogInformation("The authorization response was successfully returned to " +
                                      "'{RedirectUri}' using the form post response mode: {Response}.",
                                      notification.RedirectUri, response);

                using (var buffer = new MemoryStream())
                    using (var writer = new StreamWriter(buffer))
                    {
                        writer.WriteLine("<!doctype html>");
                        writer.WriteLine("<html>");
                        writer.WriteLine("<body>");

                        // While the redirect_uri parameter should be guarded against unknown values
                        // by OpenIdConnectServerProvider.ValidateAuthorizationRequest,
                        // it's still safer to encode it to avoid cross-site scripting attacks
                        // if the authorization server has a relaxed policy concerning redirect URIs.
                        writer.WriteLine($@"<form name=""form"" method=""post"" action=""{Options.HtmlEncoder.Encode(notification.RedirectUri)}"">");

                        foreach (var parameter in parameters)
                        {
                            var key   = Options.HtmlEncoder.Encode(parameter.Key);
                            var value = Options.HtmlEncoder.Encode(parameter.Value);

                            writer.WriteLine($@"<input type=""hidden"" name=""{key}"" value=""{value}"" />");
                        }

                        writer.WriteLine(@"<noscript>Click here to finish the authorization process: <input type=""submit"" /></noscript>");
                        writer.WriteLine("</form>");
                        writer.WriteLine("<script>document.form.submit();</script>");
                        writer.WriteLine("</body>");
                        writer.WriteLine("</html>");
                        writer.Flush();

                        Response.StatusCode    = 200;
                        Response.ContentLength = buffer.Length;
                        Response.ContentType   = "text/html;charset=UTF-8";

                        Response.Headers["Cache-Control"] = "no-cache";
                        Response.Headers["Pragma"]        = "no-cache";
                        Response.Headers["Expires"]       = "-1";

                        buffer.Seek(offset: 0, loc: SeekOrigin.Begin);
                        await buffer.CopyToAsync(Response.Body, 4096, Context.RequestAborted);

                        return(true);
                    }
            }

            case OpenIdConnectConstants.ResponseModes.Fragment:
            {
                Logger.LogInformation("The authorization response was successfully returned to " +
                                      "'{RedirectUri}' using the fragment response mode: {Response}.",
                                      notification.RedirectUri, response);

                var location = notification.RedirectUri;
                var appender = new OpenIdConnectServerHelpers.Appender(location, '#');

                foreach (var parameter in parameters)
                {
                    appender.Append(parameter.Key, parameter.Value);
                }

                Response.Redirect(appender.ToString());
                return(true);
            }

            case OpenIdConnectConstants.ResponseModes.Query:
            {
                Logger.LogInformation("The authorization response was successfully returned to " +
                                      "'{RedirectUri}' using the query response mode: {Response}.",
                                      notification.RedirectUri, response);

                var location = notification.RedirectUri;

                foreach (var parameter in parameters)
                {
                    location = QueryHelpers.AddQueryString(location, parameter.Key, parameter.Value);
                }

                Response.Redirect(location);
                return(true);
            }

            default:
            {
                Logger.LogError("The authorization request was rejected because the 'response_mode' " +
                                "parameter was invalid: {ResponseMode}.", request.ResponseMode);

                return(await SendNativePageAsync(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.InvalidRequest,
                        ErrorDescription = "The specified 'response_mode' parameter is not supported."
                    }));
            }
            }
        }
 /// <summary>
 /// Represents an event called before the authorization response is returned to the caller.
 /// </summary>
 /// <param name="context">The context instance associated with this event.</param>
 /// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
 public virtual Task ApplyAuthorizationResponse(ApplyAuthorizationResponseContext context)
 => OnApplyAuthorizationResponse(context);