public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (httpRequest == null)
            {
                throw new ArgumentNullException(nameof(httpRequest));
            }

            if (httpResponse == null)
            {
                throw new ArgumentNullException(nameof(httpResponse));
            }

            if (bot == null)
            {
                throw new ArgumentNullException(nameof(bot));
            }

            if (_authenticationProvider != null)
            {
                var authenticated = _authenticationProvider.Authenticate(httpRequest.Headers["Authorization"]);

                if (!authenticated)
                {
                    httpResponse.StatusCode = (int)HttpStatusCode.Unauthorized;
                    return;
                }
            }

            // deserialize the incoming Activity
            var activity = ReadRequest(httpRequest);

            var cancellationTokenSource = new CancellationTokenSource();

            _botTelemetryClient.TrackTrace($"SkillHttpAdapter: Processing incoming activity. Activity id: {activity.Id}", Severity.Information, null);

            // process the inbound activity with the bot
            var invokeResponse = await _skillHttpBotAdapter.ProcessActivityAsync(activity, bot.OnTurnAsync, cancellationTokenSource.Token).ConfigureAwait(false);

            // trigger cancel token after activity is handled. this will stop the typing indicator
            cancellationTokenSource.Cancel();

            // write the response, potentially serializing the InvokeResponse
            WriteResponse(httpResponse, invokeResponse);
        }