/// <summary>
        /// Validates a JWT request object
        /// </summary>
        /// <param name="client">The client</param>
        /// <param name="jwtTokenString">The JWT</param>
        /// <returns></returns>
        public virtual async Task <JwtRequestValidationResult> ValidateAsync(Client client, string jwtTokenString)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }
            if (String.IsNullOrWhiteSpace(jwtTokenString))
            {
                throw new ArgumentNullException(nameof(jwtTokenString));
            }

            var fail = new JwtRequestValidationResult {
                IsError = true
            };

            List <SecurityKey> trustedKeys;

            try
            {
                trustedKeys = await GetKeysAsync(client);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Could not parse client secrets");
                return(fail);
            }

            if (!trustedKeys.Any())
            {
                Logger.LogError("There are no keys available to validate JWT.");
                return(fail);
            }

            JwtSecurityToken jwtSecurityToken;

            try
            {
                jwtSecurityToken = await ValidateJwtAsync(jwtTokenString, trustedKeys, client);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "JWT token validation error");
                return(fail);
            }

            if (jwtSecurityToken.Payload.ContainsKey(OidcConstants.AuthorizeRequest.Request) ||
                jwtSecurityToken.Payload.ContainsKey(OidcConstants.AuthorizeRequest.RequestUri))
            {
                Logger.LogError("JWT payload must not contain request or request_uri");
                return(fail);
            }

            var payload = await ProcessPayloadAsync(jwtSecurityToken);

            var result = new JwtRequestValidationResult
            {
                IsError = false,
                Payload = payload
            };

            Logger.LogDebug("JWT request object validation success.");
            return(result);
        }
        public Task <JwtRequestValidationResult> ValidateAsync(Client client, string jwtTokenString)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }
            if (String.IsNullOrWhiteSpace(jwtTokenString))
            {
                throw new ArgumentNullException(nameof(jwtTokenString));
            }

            var fail = Task.FromResult(new JwtRequestValidationResult {
                IsError = true
            });

            var enumeratedSecrets = client.ClientSecrets.ToList().AsReadOnly();

            List <SecurityKey> trustedKeys;

            try
            {
                trustedKeys = GetKeys(enumeratedSecrets);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Could not parse client secrets");
                return(fail);
            }

            if (!trustedKeys.Any())
            {
                _logger.LogError("There are no keys available to validate JWT.");
                return(fail);
            }

            var tokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKeys        = trustedKeys,
                ValidateIssuerSigningKey = true,

                ValidIssuer    = client.ClientId,
                ValidateIssuer = true,

                ValidAudience    = _audienceUri,
                ValidateAudience = true,

                RequireSignedTokens   = true,
                RequireExpirationTime = true
            };

            try
            {
                var handler = new JwtSecurityTokenHandler();
                handler.ValidateToken(jwtTokenString, tokenValidationParameters, out var token);

                var jwtSecurityToken = (JwtSecurityToken)token;

                // todo: IdentityModel update
                if (jwtSecurityToken.Payload.ContainsKey("request") ||
                    jwtSecurityToken.Payload.ContainsKey("request_uri"))
                {
                    _logger.LogError("JWT payload must not contain request or request_uri");
                    return(fail);
                }

                // filter JWT validation values
                var payload = new Dictionary <string, string>();
                foreach (var key in jwtSecurityToken.Payload.Keys)
                {
                    if (!Constants.Filters.JwtRequestClaimTypesFilter.Contains(key))
                    {
                        var value = jwtSecurityToken.Payload[key];

                        if (value is string s)
                        {
                            payload.Add(key, s);
                        }
                        else if (value is JObject jobj)
                        {
                            payload.Add(key, jobj.ToString(Formatting.None));
                        }
                        else if (value is JArray jarr)
                        {
                            payload.Add(key, jarr.ToString(Formatting.None));
                        }
                    }
                }

                var result = new JwtRequestValidationResult
                {
                    IsError = false,
                    Payload = payload
                };

                _logger.LogDebug("JWT request object validation success.");
                return(Task.FromResult(result));
            }
            catch (Exception e)
            {
                _logger.LogError(e, "JWT token validation error");
                return(fail);
            }
        }