/// <summary>Generates a key.</summary>
 /// <param name="refreshToken">The refresh token.</param>
 /// <returns>The key.</returns>
 protected string GenerateKey(RedisRefreshToken refreshToken)
 {
     return this.Configuration.RefreshTokenPrefix + ":" + refreshToken.Id;
 }
        /// <summary>
        /// Gets all refresh tokens that matches the specified redirect uri and expires after the
        /// specified date. Called when authentication a refresh token to limit the number of tokens to
        /// go through when validating the hash.
        /// </summary>
        /// <param name="clientId">Identifier for the client.</param>
        /// <param name="redirectUri">The redirect uri.</param>
        /// <param name="expires">The expire date.</param>
        /// <returns>The refresh tokens.</returns>
        public async Task<IEnumerable<IRefreshToken>> GetRefreshTokens(string clientId, string redirectUri, DateTime expires)
        {
            var db = this.GetDatabase();

            var min = expires.ToUnixTime();
            var tokens = new List<IRefreshToken>();

            var keys = db.SortedSetRangeByScore(this.Configuration.RefreshTokenPrefix, min, DateTimeMax);

            foreach (var key in keys)
            {
                var hashedId = key.ToString().Substring(this.Configuration.RefreshTokenPrefix.Length + 1);

                var hashEntries = await db.HashGetAllAsync(key.ToString());

                if (hashEntries.Any())
                {
                    var token = new RedisRefreshToken(hashEntries) { Id = hashedId };

                    if (token.ClientId == clientId && token.RedirectUri == redirectUri)
                    {
                        tokens.Add(token);
                    }
                }
            }

            return tokens;
        }