private static void Introspection(string accessToken)
        {
            var client = new IntrospectionClient(
                "https://localhost:44333/core/connect/introspect",
                "write",
                "secret");

            var request = new IntrospectionRequest
            {
                Token = accessToken
            };

            var result = client.SendAsync(request).Result;

            if (result.IsError)
            {
                Console.WriteLine(result.Error);
            }
            else
            {
                if (result.IsActive)
                {
                    result.Claims.ToList().ForEach(c => Console.WriteLine("{0}: {1}",
                        c.Item1, c.Item2));
                }
                else
                {
                    Console.WriteLine("token is not active");
                }
            }
        }
        private static void Introspection(string accessToken)
        {
            var client = new IntrospectionClient(
                Constants.IntrospectionEndpoint,
                "api1",
                "secret");

            var request = new IntrospectionRequest
            {
                Token = accessToken
            };

            var result = client.SendAsync(request).Result;

            if (result.IsError)
            {
                Console.WriteLine(result.Error);
            }
            else
            {
                if (result.IsActive)
                {
                    result.Claims.ToList().ForEach(c => Console.WriteLine("{0}: {1}",
                        c.Item1, c.Item2));
                }
                else
                {
                    Console.WriteLine("token is not active");
                }
            }
        }
        /// <summary>
        ///   Inoltra l'access token al server di OAuth2 al fine di validarlo.
        /// </summary>
        /// <param name="owinContext">Il contesto HTTP di OWIN.</param>
        /// <param name="clientId">Il client ID a cui è legato il token.</param>
        /// <param name="accessToken">L'access token da validare.</param>
        /// <returns>
        ///   Autorizzazione positiva se il token è stato validato, negativa altrimenti. Il campo
        ///   <see cref="AuthorizationResult{TPayload}.Payload"/> deve essere valorizzato con le
        ///   informazioni sull'utente, se ricevute.
        /// </returns>
        public async Task<AuthorizationResult<UserClaimCollection>> ValidateAsync(IOwinContext owinContext, string clientId, string accessToken)
        {
            // Preconditions
            Raise.ArgumentNullException.IfIsNull(owinContext, nameof(owinContext));
            Raise.ArgumentException.IfIsNullOrWhiteSpace(clientId, nameof(clientId));
            Raise.ArgumentException.IfIsNullOrWhiteSpace(accessToken, nameof(accessToken));

            try
            {
                var address = AuthorizationSettings.AccessTokenValidationEndpointUri.AbsoluteUri;
                var clientEntry = AuthorizationSettings.Clients[clientId];

                var tokenClient = new IntrospectionClient(address, clientEntry.ScopeName, clientEntry.ScopeSecret);
                var tokenResponse = await tokenClient.SendAsync(new IntrospectionRequest
                {
                    Token = accessToken
                });

                if (tokenResponse.IsError)
                {
                    return new AuthorizationResult<UserClaimCollection>
                    {
                        Authorized = false,
                        AuthorizationDeniedReason = $"Access token validation request failed: {tokenResponse.Error}"
                    };
                }
                if (!tokenResponse.IsActive)
                {
                    return new AuthorizationResult<UserClaimCollection>
                    {
                        Authorized = false,
                        AuthorizationDeniedReason = "Access token has expired"
                    };
                }

                return new AuthorizationResult<UserClaimCollection>
                {
                    Authorized = true,
                    Payload = _mapper.Map<UserClaimCollection>(tokenResponse.Claims)
                };
            }
            catch (Exception ex)
            {
                _log.Error("Caught an exception while validating an access token", ex);
                return new AuthorizationResult<UserClaimCollection>
                {
                    Authorized = false,
                    AuthorizationDeniedReason = ex.Message,
                    AuthorizationDeniedException = ex
                };
            }
        }
        public async Task Invalid_Token()
        {
            var introspectionClient = new IntrospectionClient(
                IntrospectionEndpoint,
                "api1",
                "secret",
                _handler);

            var response = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = "invalid"
            });

            response.IsActive.Should().Be(false);
            response.IsError.Should().Be(false);
        }
        public IntrospectionEndpointTokenProvider(IdentityServerBearerTokenAuthenticationOptions options, ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.Create(this.GetType().FullName);

            if (string.IsNullOrWhiteSpace(options.Authority))
            {
                throw new Exception("Authority must be set to use validation endpoint.");
            }

            var baseAddress = options.Authority.EnsureTrailingSlash();
            baseAddress += "connect/introspect";
            var introspectionEndpoint = baseAddress;

            var handler = options.IntrospectionHttpHandler ?? new WebRequestHandler();

            if (options.BackchannelCertificateValidator != null)
            {
                // Set the cert validate callback
                var webRequestHandler = handler as WebRequestHandler;
                if (webRequestHandler == null)
                {
                    throw new InvalidOperationException("The back channel handler must derive from WebRequestHandler in order to use a certificate validator");
                }

                webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate;
            }

            if (!string.IsNullOrEmpty(options.ClientId))
            {
                _client = new IntrospectionClient(
                    introspectionEndpoint, 
                    options.ClientId, 
                    options.ClientSecret,
                    handler);
            }
            else
            {
                _client = new IntrospectionClient(
                    introspectionEndpoint,
                    innerHttpMessageHandler: handler);
            }

            _options = options;
        }
        public async Task introspecting_same_access_token_twice_should_have_same_exp()
        {
            var tokenClient = new TokenClient(TokenEndpoint, clientId, clientSecret, _handler);
            var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("bob", "bob", "api1 offline_access");

            var introspectionClient = new IntrospectionClient(IntrospectionEndpoint, scope, scopeSecret, _handler);
            var introspectionResponse1 = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = tokenResponse.AccessToken
            });

            var introspectionResponse2 = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = tokenResponse.AccessToken
            });

            var exp1 = Int32.Parse(introspectionResponse1.Claims.Single(x => x.Item1 == "exp").Item2);
            var exp2 = Int32.Parse(introspectionResponse2.Claims.Single(x => x.Item1 == "exp").Item2);

            exp1.Should().Be(exp2);
        }
        public async Task when_refreshing_new_exp_should_be_prior_to_old_exp()
        {
            var tokenClient = new TokenClient(TokenEndpoint, clientId, clientSecret, _handler);
            var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("bob", "bob", "api1 offline_access");

            var introspectionClient = new IntrospectionClient(IntrospectionEndpoint, scope, scopeSecret, _handler);
            var introspectionResponse1 = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = tokenResponse.AccessToken
            });
            var exp1 = Int32.Parse(introspectionResponse1.Claims.Single(x => x.Item1 == "exp").Item2);

            await Task.Delay(1000);

            var refreshResponse = await tokenClient.RequestRefreshTokenAsync(tokenResponse.RefreshToken);
            var introspectionResponse2 = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = refreshResponse.AccessToken
            });

            var exp2 = Int32.Parse(introspectionResponse2.Claims.Single(x => x.Item1 == "exp").Item2);

            exp1.Should().BeLessThan(exp2);
        }
        public async Task Valid_Token_Invalid_Scope()
        {
            var tokenClient = new TokenClient(
                TokenEndpoint,
                "client1",
                "secret",
                _handler);

            var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");

            var introspectionClient = new IntrospectionClient(
                IntrospectionEndpoint,
                "api2",
                "secret",
                _handler);

            var response = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = tokenResponse.AccessToken
            });

            response.IsActive.Should().Be(false);
            response.IsError.Should().Be(false);
        }
        public async Task Valid_Token_Valid_Scope_Multiple()
        {
            var tokenClient = new TokenClient(
                TokenEndpoint,
                "client1",
                "secret",
                _handler);

            var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1 api2");

            var introspectionClient = new IntrospectionClient(
                IntrospectionEndpoint,
                "api1",
                "secret",
                _handler);

            var response = await introspectionClient.SendAsync(new IntrospectionRequest
            {
                Token = tokenResponse.AccessToken
            });

            response.IsActive.Should().Be(true);
            response.IsError.Should().Be(false);

            var scopes = from c in response.Claims
                         where c.Item1 == "scope"
                         select c;

            scopes.Count().Should().Be(1);
            scopes.First().Item2.Should().Be("api1");
        }