public async Task <AuthorizeRequestValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject = null)
        {
            Logger.Info("Start authorize request protocol validation");

            var request = new ValidatedAuthorizeRequest
            {
                Options = _options,
                Subject = subject ?? Principal.Anonymous
            };

            if (parameters == null)
            {
                Logger.Error("Parameters are null.");
                throw new ArgumentNullException("parameters");
            }

            request.Raw = parameters;

            // validate client_id and redirect_uri
            var clientResult = await ValidateClientAsync(request);

            if (clientResult.IsError)
            {
                return(clientResult);
            }

            // state, response_type, response_mode
            var mandatoryResult = ValidateCoreParameters(request);

            if (mandatoryResult.IsError)
            {
                return(mandatoryResult);
            }

            // scope, scope restrictions and plausability
            var scopeResult = await ValidateScopeAsync(request);

            if (scopeResult.IsError)
            {
                return(scopeResult);
            }

            // nonce, prompt, acr_values, login_hint etc.
            var optionalResult = ValidateOptionalParameters(request);

            if (optionalResult.IsError)
            {
                return(optionalResult);
            }

            // custom validator
            var customResult = await _customValidator.ValidateAuthorizeRequestAsync(request);

            if (customResult.IsError)
            {
                LogError("Error in custom validation: " + customResult.Error, request);
                return(Invalid(request, customResult.ErrorType, customResult.Error));
            }

            LogSuccess(request);
            return(Valid(request));
        }
        private AuthorizeRequestValidationResult ValidateOptionalParameters(ValidatedAuthorizeRequest request)
        {
            //////////////////////////////////////////////////////////
            // check nonce
            //////////////////////////////////////////////////////////
            var nonce = request.Raw.Get(Constants.AuthorizeRequest.Nonce);

            if (nonce.IsPresent())
            {
                if (nonce.Length > Constants.MaxNonceLength)
                {
                    LogError("Nonce too long", request);
                    return(Invalid(request, ErrorTypes.Client));
                }

                request.Nonce = nonce;
            }
            else
            {
                if (request.Flow == Flows.Implicit)
                {
                    // only openid requests require nonce
                    if (request.IsOpenIdRequest)
                    {
                        LogError("Nonce required for implicit flow with openid scope", request);
                        return(Invalid(request, ErrorTypes.Client));
                    }
                }
            }


            //////////////////////////////////////////////////////////
            // check prompt
            //////////////////////////////////////////////////////////
            var prompt = request.Raw.Get(Constants.AuthorizeRequest.Prompt);

            if (prompt.IsPresent())
            {
                if (Constants.SupportedPromptModes.Contains(prompt))
                {
                    request.PromptMode = prompt;
                }
                else
                {
                    Logger.Info("Unsupported prompt mode - ignored: " + prompt);
                }
            }

            //////////////////////////////////////////////////////////
            // check ui locales
            //////////////////////////////////////////////////////////
            var uilocales = request.Raw.Get(Constants.AuthorizeRequest.UiLocales);

            if (uilocales.IsPresent())
            {
                if (uilocales.Length > Constants.MaxUiLocaleLength)
                {
                    LogError("UI locale too long", request);
                    return(Invalid(request, ErrorTypes.Client));
                }

                request.UiLocales = uilocales;
            }

            //////////////////////////////////////////////////////////
            // check display
            //////////////////////////////////////////////////////////
            var display = request.Raw.Get(Constants.AuthorizeRequest.Display);

            if (display.IsPresent())
            {
                if (Constants.SupportedDisplayModes.Contains(display))
                {
                    request.DisplayMode = display;
                }

                Logger.Info("Unsupported display mode - ignored: " + display);
            }

            //////////////////////////////////////////////////////////
            // check max_age
            //////////////////////////////////////////////////////////
            var maxAge = request.Raw.Get(Constants.AuthorizeRequest.MaxAge);

            if (maxAge.IsPresent())
            {
                int seconds;
                if (int.TryParse(maxAge, out seconds))
                {
                    if (seconds >= 0)
                    {
                        request.MaxAge = seconds;
                    }
                    else
                    {
                        LogError("Invalid max_age.", request);
                        return(Invalid(request, ErrorTypes.Client));
                    }
                }
                else
                {
                    LogError("Invalid max_age.", request);
                    return(Invalid(request, ErrorTypes.Client));
                }
            }

            //////////////////////////////////////////////////////////
            // check login_hint
            //////////////////////////////////////////////////////////
            var loginHint = request.Raw.Get(Constants.AuthorizeRequest.LoginHint);

            if (loginHint.IsPresent())
            {
                if (loginHint.Length > Constants.MaxLoginHintLength)
                {
                    LogError("Login hint too long", request);
                    return(Invalid(request, ErrorTypes.Client));
                }

                request.LoginHint = loginHint;
            }

            //////////////////////////////////////////////////////////
            // check acr_values
            //////////////////////////////////////////////////////////
            var acrValues = request.Raw.Get(Constants.AuthorizeRequest.AcrValues);

            if (acrValues.IsPresent())
            {
                if (acrValues.Length > Constants.MaxAcrValuesLength)
                {
                    LogError("Acr values too long", request);
                    return(Invalid(request, ErrorTypes.Client));
                }

                request.AuthenticationContextReferenceClasses = acrValues.FromSpaceSeparatedString().Distinct().ToList();
            }

            //////////////////////////////////////////////////////////
            // check session cookie
            //////////////////////////////////////////////////////////
            if (_options.Endpoints.EnableCheckSessionEndpoint &&
                request.Subject.Identity.IsAuthenticated)
            {
                var sessionId = _sessionCookie.GetSessionId();
                if (sessionId.IsPresent())
                {
                    request.SessionId = sessionId;
                }
                else
                {
                    LogError("Check session endpoint enabled, but SessionId is missing", request);
                }
            }

            return(Valid(request));
        }
        private AuthorizeRequestValidationResult ValidateCoreParameters(ValidatedAuthorizeRequest request)
        {
            //////////////////////////////////////////////////////////
            // check state
            //////////////////////////////////////////////////////////
            var state = request.Raw.Get(Constants.AuthorizeRequest.State);

            if (state.IsPresent())
            {
                request.State = state;
            }

            //////////////////////////////////////////////////////////
            // response_type must be present and supported
            //////////////////////////////////////////////////////////
            var responseType = request.Raw.Get(Constants.AuthorizeRequest.ResponseType);

            if (responseType.IsMissing())
            {
                LogError("Missing response_type", request);
                return(Invalid(request, ErrorTypes.Client, Constants.AuthorizeErrors.UnsupportedResponseType));
            }

            if (!Constants.SupportedResponseTypes.Contains(responseType))
            {
                LogError("Response type not supported: " + responseType, request);
                return(Invalid(request, ErrorTypes.Client, Constants.AuthorizeErrors.UnsupportedResponseType));
            }

            request.ResponseType = responseType;


            //////////////////////////////////////////////////////////
            // match response_type to flow
            //////////////////////////////////////////////////////////
            request.Flow = Constants.ResponseTypeToFlowMapping[request.ResponseType];


            //////////////////////////////////////////////////////////
            // check if flow is allowed at authorize endpoint
            //////////////////////////////////////////////////////////
            if (!Constants.AllowedFlowsForAuthorizeEndpoint.Contains(request.Flow))
            {
                LogError("Invalid flow", request);
                return(Invalid(request));
            }

            //////////////////////////////////////////////////////////
            // check response_mode parameter and set response_mode
            //////////////////////////////////////////////////////////

            // set default response mode for flow first
            request.ResponseMode = Constants.AllowedResponseModesForFlow[request.Flow].First();

            // check if response_mode parameter is present and valid
            var responseMode = request.Raw.Get(Constants.AuthorizeRequest.ResponseMode);

            if (responseMode.IsPresent())
            {
                if (Constants.SupportedResponseModes.Contains(responseMode))
                {
                    if (Constants.AllowedResponseModesForFlow[request.Flow].Contains(responseMode))
                    {
                        request.ResponseMode = responseMode;
                    }
                    else
                    {
                        LogError("Invalid response_mode for flow: " + responseMode, request);
                        return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnsupportedResponseType));
                    }
                }
                else
                {
                    LogError("Unsupported response_mode: " + responseMode, request);
                    return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnsupportedResponseType));
                }
            }


            //////////////////////////////////////////////////////////
            // check if flow is allowed for client
            //////////////////////////////////////////////////////////
            if (request.Flow != request.Client.Flow)
            {
                LogError("Invalid flow for client: " + request.Flow, request);
                return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnauthorizedClient));
            }

            return(Valid(request));
        }
        private async Task <AuthorizeRequestValidationResult> ValidateScopeAsync(ValidatedAuthorizeRequest request)
        {
            //////////////////////////////////////////////////////////
            // scope must be present
            //////////////////////////////////////////////////////////
            var scope = request.Raw.Get(Constants.AuthorizeRequest.Scope);

            if (scope.IsMissing())
            {
                LogError("scope is missing", request);
                return(Invalid(request, ErrorTypes.Client));
            }

            if (scope.Length > Constants.MaxScopeLength)
            {
                LogError("scopes too long.", request);
                return(Invalid(request, ErrorTypes.Client));
            }

            request.RequestedScopes = scope.FromSpaceSeparatedString().Distinct().ToList();

            if (request.RequestedScopes.Contains(Constants.StandardScopes.OpenId))
            {
                request.IsOpenIdRequest = true;
            }

            //////////////////////////////////////////////////////////
            // check scope vs response_type plausability
            //////////////////////////////////////////////////////////
            var requirement = Constants.ResponseTypeToScopeRequirement[request.ResponseType];

            if (requirement == Constants.ScopeRequirement.Identity ||
                requirement == Constants.ScopeRequirement.IdentityOnly)
            {
                if (request.IsOpenIdRequest == false)
                {
                    LogError("response_type requires the openid scope", request);
                    return(Invalid(request, ErrorTypes.Client));
                }
            }

            //////////////////////////////////////////////////////////
            // check if scopes are valid/supported and check for resource scopes
            //////////////////////////////////////////////////////////
            if (await _scopeValidator.AreScopesValidAsync(request.RequestedScopes) == false)
            {
                return(Invalid(request, ErrorTypes.Client, Constants.AuthorizeErrors.InvalidScope));
            }

            if (_scopeValidator.ContainsOpenIdScopes && !request.IsOpenIdRequest)
            {
                LogError("Identity related scope requests, but no openid scope", request);
                return(Invalid(request, ErrorTypes.Client, Constants.AuthorizeErrors.InvalidScope));
            }

            if (_scopeValidator.ContainsResourceScopes)
            {
                request.IsResourceRequest = true;
            }

            //////////////////////////////////////////////////////////
            // check scopes and scope restrictions
            //////////////////////////////////////////////////////////
            if (!_scopeValidator.AreScopesAllowed(request.Client, request.RequestedScopes))
            {
                return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnauthorizedClient));
            }

            request.ValidatedScopes = _scopeValidator;

            //////////////////////////////////////////////////////////
            // check id vs resource scopes and response types plausability
            //////////////////////////////////////////////////////////
            if (!_scopeValidator.IsResponseTypeValid(request.ResponseType))
            {
                return(Invalid(request, ErrorTypes.Client, Constants.AuthorizeErrors.InvalidScope));
            }

            return(Valid(request));
        }
        public async Task <AuthorizeRequestValidationResult> ValidateClientAsync(ValidatedAuthorizeRequest request)
        {
            //////////////////////////////////////////////////////////
            // client_id must be present
            /////////////////////////////////////////////////////////
            var clientId = request.Raw.Get(Constants.AuthorizeRequest.ClientId);

            if (clientId.IsMissingOrTooLong(Constants.MaxClientIdLength))
            {
                LogError("client_id is missing or too long", request);
                return(Invalid(request));
            }

            request.ClientId = clientId;


            //////////////////////////////////////////////////////////
            // redirect_uri must be present, and a valid uri
            //////////////////////////////////////////////////////////
            var redirectUri = request.Raw.Get(Constants.AuthorizeRequest.RedirectUri);

            if (redirectUri.IsMissingOrTooLong(Constants.MaxRedirectUriLength))
            {
                LogError("redirect_uri is missing or too long", request);
                return(Invalid(request));
            }

            Uri uri;

            if (!Uri.TryCreate(redirectUri, UriKind.Absolute, out uri))
            {
                LogError("invalid redirect_uri: " + redirectUri, request);
                return(Invalid(request));
            }

            request.RedirectUri = redirectUri;


            //////////////////////////////////////////////////////////
            // check for valid client
            //////////////////////////////////////////////////////////
            var client = await _clients.FindClientByIdAsync(request.ClientId);

            if (client == null || client.Enabled == false)
            {
                LogError("Unknown client or not enabled: " + request.ClientId, request);
                return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnauthorizedClient));
            }

            request.Client = client;

            //////////////////////////////////////////////////////////
            // check if redirect_uri is valid
            //////////////////////////////////////////////////////////
            if (await _uriValidator.IsRedirectUriValidAsync(request.RedirectUri, request.Client) == false)
            {
                LogError("Invalid redirect_uri: " + request.RedirectUri, request);
                return(Invalid(request, ErrorTypes.User, Constants.AuthorizeErrors.UnauthorizedClient));
            }

            return(Valid(request));
        }