private async Task<AccessTokenIntrospectionResult> IntrospectTokenOnlineAsync(string accessToken, 
            AccessTokenType accessTokenType, DiscoveryDocumentShortInfo discoveryDocument)
        {

            // TODO: This approach should be reconsidered in future.
            /*
            The solution below allows use "Orleans.Security" with IdentityServer4 v2.x and IdentityServer4 v3.x.
            At the same time, DLR with Reflection in is a bad idea.
            */

            const string fullyQualifiedNameOfType =
                "IdentityModel.Client.HttpClientTokenIntrospectionExtensions, IdentityModel";

            dynamic request = 
                Activator.CreateInstance(Type.GetType("IdentityModel.Client.TokenIntrospectionRequest, IdentityModel", 
                    true));

            request.Address = discoveryDocument.IntrospectionEndpoint;
            request.ClientId = _identityServer4Info.ClientId;
            request.Token = accessToken;
            request.ClientSecret = _identityServer4Info.ClientSecret;

            var cancellationToken = default(CancellationToken);
            var param = new object[] { _httpClient,request, cancellationToken };

            var introspectionResponse =
                await RuntimeMethodBinder.InvokeAsync(fullyQualifiedNameOfType,
                    "IntrospectTokenAsync", param, 3);

            // TODO: This should be used normally.

            /*
            var request = new TokenIntrospectionRequest
            {
                Address = discoveryDocument.IntrospectionEndpoint,
                ClientId = _identityServer4Info.ClientId,
                Token = accessToken,
                ClientSecret = _identityServer4Info.ClientSecret,
            };
            
            var introspectionResponse = await _httpClient.IntrospectTokenAsync(request);
            */

            var nameOfTokenType = accessTokenType == AccessTokenType.Jwt ? "JWT" : "Reference";
            
            // ReSharper disable once ConvertIfStatementToReturnStatement
            if (!introspectionResponse.IsError)
            {
                return new AccessTokenIntrospectionResult(accessTokenType, introspectionResponse.Claims,
                    introspectionResponse.IsActive);
            }

            _logger.LogTrace(LoggingEvents.AccessTokenValidationFailed,
                $"{LoggingEvents.AccessTokenValidationFailed.Name} Token type: {nameOfTokenType} " +
                $"Reason: {introspectionResponse.Error} " +
                $"Token value: {accessToken}");
                
            return new AccessTokenIntrospectionResult(accessTokenType, introspectionResponse.Claims, false);
        }
        internal static IEnumerable <Claim> Verify(string jwt, string audience,
                                                   DiscoveryDocumentShortInfo discoveryDocument)
        {
            var keys = new List <SecurityKey>();

            foreach (var webKey in discoveryDocument.Keys)
            {
                var e = Base64Url.Decode(webKey.E);
                var n = Base64Url.Decode(webKey.N);

                var key = new RsaSecurityKey(new RSAParameters {
                    Exponent = e, Modulus = n
                })
                {
                    KeyId = webKey.Kid
                };

                keys.Add(key);
            }

            var parameters = new TokenValidationParameters
            {
                ValidIssuer       = discoveryDocument.Issuer,
                ValidAudience     = audience,
                IssuerSigningKeys = keys,

                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,

                RequireSignedTokens = true
            };

            var handler = new JwtSecurityTokenHandler();

            handler.InboundClaimTypeMap.Clear();

            var claimsPrincipal = handler.ValidateToken(jwt, parameters, out var validatedToken);

            return(claimsPrincipal.Claims);
        }