public async Task <ClientRecord> FetchClientRecordAsync(string scheme, string clientId)
        {
            var key    = $"{scheme}.{clientId}";
            var result = await _cacheClientRecord.GetAsync(key,
                                                           CachingExpiration,
                                                           () => _inner.FetchClientRecordAsync(scheme, clientId),
                                                           _logger);

            return(result);
        }
        public async Task <AuthorizeRequestValidationResult> ValidateAsync(ValidatedAuthorizeRequest request)
        {
            var parameters = request.Raw;

            request.Nonce = parameters.Get(OidcConstants.AuthorizeRequest.Nonce);

            var state = parameters.Get(OidcConstants.AuthorizeRequest.State);

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

            //////////////////////////////////////////////////////////
            // redirect_uri must be present and supported
            //////////////////////////////////////////////////////////
            var redirectUri = parameters.Get(OidcConstants.AuthorizeRequest.RedirectUri);

            if (redirectUri.IsMissing())
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.RedirectUri}");
                return(Invalid(request, OidcConstants.AuthorizeErrors.InvalidRequestUri, $"Missing {OidcConstants.AuthorizeRequest.RedirectUri}"));
            }

            //////////////////////////////////////////////////////////
            // response_type must be present and supported
            //////////////////////////////////////////////////////////
            var responseType = parameters.Get(OidcConstants.AuthorizeRequest.ResponseType);

            if (responseType.IsMissing())
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.ResponseType}");
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnsupportedResponseType, $"Missing {OidcConstants.AuthorizeRequest.ResponseType}"));
            }
            if (!SupportedResponseTypes.Contains(responseType, _responseTypeEqualityComparer))
            {
                _logger.LogError("Response type not supported", responseType);
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnsupportedResponseType, "Response type not supported"));
            }
            request.ResponseType = SupportedResponseTypes.First(
                supportedResponseType => _responseTypeEqualityComparer.Equals(supportedResponseType, responseType));

            //////////////////////////////////////////////////////////
            // match response_type to grant type
            //////////////////////////////////////////////////////////
            request.GrantType = Constants.ResponseTypeToGrantTypeMapping[responseType];
            //////////////////////////////////////////////////////////
            // check if flow is allowed at authorize endpoint
            //////////////////////////////////////////////////////////
            if (!Constants.AllowedGrantTypesForAuthorizeEndpoint.Contains(request.GrantType))
            {
                LogError("Invalid grant type", request.GrantType, request);
                return(Invalid(request, description: "Invalid response_type"));
            }

            // set default response mode for flow; this is needed for any client error processing below
            request.ResponseMode = Constants.AllowedResponseModesForGrantType[request.GrantType].First();

            //////////////////////////////////////////////////////////
            // client_id must be present and supported
            //////////////////////////////////////////////////////////

            request.ClientId = parameters.Get(OidcConstants.AuthorizeRequest.ClientId);


            if (request.ClientId.IsMissing())
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.ClientId}");
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Missing {OidcConstants.AuthorizeRequest.ClientId}"));
            }
            //////////////////////////////////////////////////////////
            // redirect_uri must be present, and a valid uri
            //////////////////////////////////////////////////////////
            request.RedirectUri = parameters.Get(OidcConstants.AuthorizeRequest.RedirectUri);

            if (request.RedirectUri.IsMissing())
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.RedirectUri}");
                return(Invalid(request, OidcConstants.AuthorizeRequest.RedirectUri, $"Missing {OidcConstants.AuthorizeRequest.RedirectUri}"));
            }

            var clientRecord = await _clientSecretStore.FetchClientRecordAsync(_options.Scheme, request.ClientId);

            if (clientRecord == null)
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.ClientId}");
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Missing {OidcConstants.AuthorizeRequest.ClientId}"));
            }
            if (!clientRecord.RedirectUris.Contains(request.RedirectUri))
            {
                _logger.LogError($"Missing {OidcConstants.AuthorizeRequest.RedirectUri}");
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Missing {OidcConstants.AuthorizeRequest.ClientId}"));
            }

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

            // check if response_mode parameter is present and valid
            var responseMode = parameters.Get(OidcConstants.AuthorizeRequest.ResponseMode);

            if (responseMode.IsPresent())
            {
                if (Constants.SupportedResponseModes.Contains(responseMode))
                {
                    if (Constants.AllowedResponseModesForGrantType[request.GrantType].Contains(responseMode))
                    {
                        request.ResponseMode = responseMode;
                    }
                    else
                    {
                        LogError("Invalid response_mode for flow", responseMode, request);
                        return(Invalid(request, OidcConstants.AuthorizeErrors.UnsupportedResponseType, description: "Invalid response_mode"));
                    }
                }
                else
                {
                    LogError("Unsupported response_mode", responseMode, request);
                    return(Invalid(request, OidcConstants.AuthorizeErrors.UnsupportedResponseType, description: "Invalid response_mode"));
                }
            }
            //////////////////////////////////////////////////////////
            // check if PKCE is required and validate parameters
            //////////////////////////////////////////////////////////
            if (request.GrantType == GrantType.AuthorizationCode || request.GrantType == GrantType.Hybrid)
            {
                _logger.LogDebug("Checking for PKCE parameters");

                /////////////////////////////////////////////////////////////////////////////
                // validate code_challenge and code_challenge_method
                /////////////////////////////////////////////////////////////////////////////
                var proofKeyResult = ValidatePkceParameters(request);

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

            return(Valid(request));
        }