public async Task <AuthenticationResult> AuthenticateAsync(AuthenticateInstruction instruction)
        {
            if (instruction == null)
            {
                throw new ArgumentNullException(nameof(instruction));
            }

            Models.Client client = null;
            // First we try to fetch the client_id
            // The different client authentication mechanisms are described here : http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
            var clientId = TryGettingClientId(instruction);

            if (!string.IsNullOrWhiteSpace(clientId))
            {
                client = await _clientRepository.GetClientByIdAsync(clientId);
            }

            if (client == null)
            {
                return(new AuthenticationResult(null, ErrorDescriptions.TheClientCannotBeAuthenticated));
            }

            var tokenEndPointAuthMethod = client.TokenEndPointAuthMethod;
            var authenticationType      = Enum.GetName(typeof(TokenEndPointAuthenticationMethods),
                                                       tokenEndPointAuthMethod);

            _simpleIdentityServerEventSource.StartToAuthenticateTheClient(client.ClientId,
                                                                          authenticationType);
            var errorMessage = string.Empty;

            switch (tokenEndPointAuthMethod)
            {
            case TokenEndPointAuthenticationMethods.client_secret_basic:
                client = _clientSecretBasicAuthentication.AuthenticateClient(instruction, client);
                if (client == null)
                {
                    errorMessage = ErrorDescriptions.TheClientCannotBeAuthenticatedWithSecretBasic;
                }
                break;

            case TokenEndPointAuthenticationMethods.client_secret_post:
                client = _clientSecretPostAuthentication.AuthenticateClient(instruction, client);
                if (client == null)
                {
                    errorMessage = ErrorDescriptions.TheClientCannotBeAuthenticatedWithSecretPost;
                }
                break;

            case TokenEndPointAuthenticationMethods.client_secret_jwt:
                if (client.Secrets == null || !client.Secrets.Any(s => s.Type == ClientSecretTypes.SharedSecret))
                {
                    errorMessage = string.Format(ErrorDescriptions.TheClientDoesntContainASharedSecret, client.ClientId);
                    break;
                }
                return(await _clientAssertionAuthentication.AuthenticateClientWithClientSecretJwtAsync(instruction, client.Secrets.First(s => s.Type == ClientSecretTypes.SharedSecret).Value));

            case TokenEndPointAuthenticationMethods.private_key_jwt:
                return(await _clientAssertionAuthentication.AuthenticateClientWithPrivateKeyJwtAsync(instruction));

            case TokenEndPointAuthenticationMethods.tls_client_auth:
                client = _clientTlsAuthentication.AuthenticateClient(instruction, client);
                if (client == null)
                {
                    errorMessage = ErrorDescriptions.TheClientCannotBeAuthenticatedWithTls;
                }
                break;
            }

            if (client != null)
            {
                _simpleIdentityServerEventSource.FinishToAuthenticateTheClient(client.ClientId,
                                                                               authenticationType);
            }

            return(new AuthenticationResult(client, errorMessage));
        }