/// <summary>
        /// Creates a result that indicates an error.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        protected virtual EndSessionValidationResult Invalid(string message, ValidatedEndSessionRequest request = null)
        {
            message = "End session request validation failure: " + message;
            if (request != null)
            {
                var log = new EndSessionRequestValidationLog(request);
                Logger.LogInformation(message + Environment.NewLine + "{@details}", log);
            }
            else
            {
                Logger.LogInformation(message);
            }

            return(new EndSessionValidationResult
            {
                IsError = true,
                Error = "Invalid request",
                ErrorDescription = message
            });
        }
        /// <summary>
        /// Logs a success result.
        /// </summary>
        /// <param name="request"></param>
        protected virtual void LogSuccess(ValidatedEndSessionRequest request)
        {
            var log = new EndSessionRequestValidationLog(request);

            Logger.LogInformation("End session request validation success" + Environment.NewLine + "{@details}", log);
        }
        /// <inheritdoc />
        public async Task <EndSessionValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject)
        {
            Logger.LogDebug("Start end session request validation");

            var isAuthenticated = subject.IsAuthenticated();

            if (!isAuthenticated && Options.Authentication.RequireAuthenticatedUserForSignOutMessage)
            {
                return(Invalid("User is anonymous. Ignoring end session parameters"));
            }

            var validatedRequest = new ValidatedEndSessionRequest
            {
                Raw = parameters
            };

            var idTokenHint = parameters.Get(OidcConstants.EndSessionRequest.IdTokenHint);

            if (idTokenHint.IsPresent())
            {
                // validate id_token - no need to validate token life time
                var tokenValidationResult = await TokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false);

                if (tokenValidationResult.IsError)
                {
                    return(Invalid("Error validating id token hint", validatedRequest));
                }

                validatedRequest.Client = tokenValidationResult.Client;

                // validate sub claim against currently logged on user
                var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
                if (subClaim != null && isAuthenticated)
                {
                    if (subject.GetSubjectId() != subClaim.Value)
                    {
                        return(Invalid("Current user does not match identity token", validatedRequest));
                    }

                    validatedRequest.Subject   = subject;
                    validatedRequest.SessionId = await UserSession.GetSessionIdAsync();

                    validatedRequest.ClientIds = await UserSession.GetClientListAsync();
                }

                var redirectUri = parameters.Get(OidcConstants.EndSessionRequest.PostLogoutRedirectUri);
                if (redirectUri.IsPresent())
                {
                    if (await UriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, validatedRequest.Client))
                    {
                        validatedRequest.PostLogOutUri = redirectUri;
                    }
                    else
                    {
                        Logger.LogWarning("Invalid PostLogoutRedirectUri: {postLogoutRedirectUri}", redirectUri);
                    }
                }

                if (validatedRequest.PostLogOutUri != null)
                {
                    var state = parameters.Get(OidcConstants.EndSessionRequest.State);
                    if (state.IsPresent())
                    {
                        validatedRequest.State = state;
                    }
                }
            }
            else
            {
                // no id_token to authenticate the client, but we do have a user and a user session
                validatedRequest.Subject   = subject;
                validatedRequest.SessionId = await UserSession.GetSessionIdAsync();

                validatedRequest.ClientIds = await UserSession.GetClientListAsync();
            }

            LogSuccess(validatedRequest);

            return(new EndSessionValidationResult
            {
                ValidatedRequest = validatedRequest,
                IsError = false
            });
        }