events.action: opened
events.author: mcinnes01
events.masked_author: username_0
events.text: Hi,
  
  In order to authenticate a user of my bot with our main product, I create LoginCard with a button that has a link to register page for their particular tenant. The url contains a query string containing the ConversationReference and a bot ID and then our main product (which doesn't contain any botframework packages) calls an endpoint on my bot.
  
  The payload contains the bot ID, and the Conversation Reference, along with a refresh token. This used to allow me to resume my conversation and then call our oAuth endpoints on our main product to get an access token from the refresh token. I then use the access token to authenticate any requests to our main product.
  
  Previously this was handled by a standard controller and then I did the following:
  
  ```
  		[HttpPost]
  		public async Task<HttpResponseMessage> RegisterConversation([FromBody] RegistrationRequest registration)
  		{
  			if (registration == null || registration.SharedKey != _interactkey)
  			{
  				return Request.CreateResponse(HttpStatusCode.BadRequest);
  			}
  
  			// Construct an activity from the resumption cookie
  			// Currently a bug in the botbuilder so using a work around for now this is what it should be eventually
  			//var conversationReference = Microsoft.Bot.Builder.ConnectorEx.ConversationReferenceHelpers.GZipDeserialize(registration.State);
  			var conversationReference = ConversationReferenceHelpers.GZipDeserializer(registration.State);
  			var activity = conversationReference.GetPostToBotMessage();
  
  			using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
  			{
  				try
  				{
  					var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
  					var key = Address.FromActivity(activity);
  					var userData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, CancellationToken.None);
  
  					// Retrieve the site info from the user data
  					var siteInfo = userData.GetProperty<SiteInfo>(StateType.SiteInfo.GetDescription());
  
  					// If there is no site info, the user needs to setup an intranet
  					if (siteInfo == null)
  					{
  						try
  						{
  							var dialog = scope.Resolve<IDialog<object>>();
  							await Conversation.SendAsync(activity, () => dialog);
  							return Request.CreateResponse(HttpStatusCode.NotFound);
  						}
  						catch (Exception conversationException)
  						{
  							return Request.CreateErrorResponse(HttpStatusCode.BadRequest, conversationException);
  						}
  					}
  
  					// Add the token to the site info
  					siteInfo.RefreshToken = registration.RefreshToken;
  					userData.SetProperty(StateType.SiteInfo.GetDescription(), siteInfo);
  
  					await botDataStore.SaveAsync(key, BotStoreType.BotUserData, userData, CancellationToken.None);
  					await botDataStore.FlushAsync(key, CancellationToken.None);
  
  					// Reply to the conversation
  					await Conversation.ResumeAsync(conversationReference, activity);
  					return Request.CreateResponse(HttpStatusCode.OK);
  				}
  				catch (Exception ex)
  				{
  					return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
  				}
  			}
  		}
  ```
  
  I am now using v4 SDK with netcore so I've built my own message handler, following the structure of the proactive message handle. I've notice during this process there are some subtle difference between master and the 4.0.1 preview branch, but I've kept my code inline with the preview for now:
  
  ```
      public class InteractBotAuthenticationHandler : BotMessageHandlerBase
  	{
  		public InteractBotAuthenticationHandler(BotFrameworkAdapter botFrameworkAdapter) : base(botFrameworkAdapter)
  		{
  		}
  
  		protected override async Task<InvokeResponse> ProcessMessageRequestAsync(HttpRequest request, BotFrameworkAdapter botFrameworkAdapter, Func<ITurnContext, Task> botCallbackHandler)
  		{
  			const string BotAppIdHttpHeaderName = "MS-BotFramework-BotAppId";
  			const string BotIdQueryStringParameterName = "BotAppId";
  
  			if (!request.Headers.TryGetValue(BotAppIdHttpHeaderName, out var botAppIdHeaders))
  			{
  				if (!request.Query.TryGetValue(BotIdQueryStringParameterName, out botAppIdHeaders))
  				{
  					throw new InvalidOperationException($"Expected a Bot App ID in a header named \"{BotAppIdHttpHeaderName}\" or in a querystring parameter named \"{BotIdQueryStringParameterName}\".");
  				}
  			}
  
  			var botAppId = botAppIdHeaders.First();
  			ConversationReference conversationReference;
  
  			using (var bodyReader = new JsonTextReader(new StreamReader(request.Body, Encoding.UTF8)))
  			{
  				var registrationResponse = BotMessageHandlerBase.BotMessageSerializer.Deserialize<RegistrationRequest>(bodyReader);
  				if (registrationResponse == null)
  					return null;
  
  				conversationReference = ConversationReferenceHelpers.GZipDeserializer(registrationResponse.State);
  
  				using (var context = new TurnContext(botFrameworkAdapter, conversationReference.GetPostToBotMessage()))
  				{
  					var userState = context.GetUserState<BotUserState>().User;
  					userState.RefreshToken = registrationResponse.RefreshToken;
  					
  				}
  			}
  
  			await botFrameworkAdapter.ContinueConversation(botAppId, conversationReference, botCallbackHandler);
  
  			return null;
  		}
  	}
  ```
  
  And here is my application builder extension:
  
  ```
  	public static class ApplicationBuilderExtensions
  	{
  		private const string AuthenticatorPath = "/api/machine";
  
  		public static IApplicationBuilder UseInteractBotAuthenticator(this IApplicationBuilder applicationBuilder)
  		{
  			if (applicationBuilder == null)
  			{
  				throw new ArgumentNullException(nameof(applicationBuilder));
  			}
  
  			var options = applicationBuilder.ApplicationServices.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
  			var botFrameworkAdapter = new BotFrameworkAdapter(options.CredentialProvider, options.ConnectorClientRetryPolicy);
  
  			foreach (var middleware in options.Middleware)
  			{
  				botFrameworkAdapter.Use(middleware);
  			}
  
  			applicationBuilder.Map(AuthenticatorPath, botActivitiesAppBuilder
  				=> botActivitiesAppBuilder.Run(new InteractBotAuthenticationHandler(botFrameworkAdapter).HandleAsync));
  
  			return applicationBuilder;
  		}
  	}
  ```
  I've then registered this in the configure section of my bot's startup, but when I try to hit the endpoint it doesn't seem to invoke my new handler and doesn't hit any endpoints.
  
  Is there something I am missing or is there a workaround for getting the proactive handler to take a payload?
  
  Many thanks
  
  Andy
events.title: Proactive message with payload
events.type: issue
events.action: created
events.author: mcinnes01
events.masked_author: username_0
events.text: Just wondered if there is any update, I still haven't managed to successfully continue a conversation? 
  
  I wonder does this perhaps have anything to do with no using an MicrosoftAppId or Password whilst debugging, and perhaps an empty string is not handled or the bot ID isn't being defaulted to "default-bot" for continuing a conversation?
events.type: comment
events.action: created
events.author: JonathanFingold
events.masked_author: username_1
events.text: @username_0 Have you tried using a custom, bot-wide state? The [v4 proactive messages](https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages) sample uses one, and seems very close to what you're describing. There is a corresponding [how-to](https://docs.microsoft.com/azure/bot-service/bot-builder-howto-proactive-message?view=azure-bot-service-4.0) article that goes into a little more depth.
events.type: comment
events.action: created
events.author: gabog
events.masked_author: username_2
events.text: Closing as part of R10 triage.
events.type: comment
events.action: closed
events.author: gabog
events.masked_author: username_2
events.type: issue