Reply to bot from web API - c#

In short, I'm trying to resume a conversation with a bot after a successful web API login. But I'm having trouble sending a reply to the bot. I have the ChannedId as well as the UserId. I'm not sure whether this is enough. I'm also not sure how to construct a new ConversationReference, which from my understanding is required to perform the reply (Conversation.ResumeAsync)
I have looked at the following example: MicrosoftDX/AuthBot, but the example uses ResumptionCookie which is deprecated. Furthermore, the example utilizes Azure AD authentication. I use cookie authentication in my web API
I require a response from my web API to continue the login form flow on the bot.
var conversationReference = ???;
// Create the message that is send to conversation to resume the login flow
var message = conversationReference.GetPostToUserMessage();
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var client = scope.Resolve<IConnectorClient>();
var sc = scope.Resolve<IStateClient>();
await Conversation.ResumeAsync(conversationReference, message);
}

Related

Sending a chat message with Microsoft Teams

Is there anyway to send a teams message to a channel or chat that doesn't involve the end user of an app being asked to sign in? What I am trying to do is something like this:
User does something on my web app
Without user interaction, my web app sends a message to a chat or channel on Microsoft Teams
I tried to send it as myself for testing (planned on using a service account later), but after some reading, I've come to find out isn't possible using application API permissions, as documented here:
Here is the code I have that would work if I wasn't using application permissions:
var tenantId = "...";
var clientId = "...";
var clientSecret = "...";
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential);
var chatMessage = new ChatMessage
{
Body = new ItemBody
{
Content = "Hello World"
}
};
await graphClient.Teams["..."].Channels["..."].Messages.Request().AddAsync(chatMessage);
It throws this exception:
Microsoft.Graph.ServiceException: 'Code: Unauthorized
Message: Message POST is allowed in application-only context only for import purposes. Refer to https://docs.microsoft.com/microsoftteams/platform/graph-api/import-messages/import-external-messages-to-teams for more details.
Inner error:
AdditionalData:
date: 2023-02-16T04:46:02
request-id: 3cbd9dc8-a86a-43e9-a5fe-e9e9b3433566
client-request-id: 3cbd9dc8-a86a-43e9-a5fe-e9e9b3433566
ClientRequestId: 3cbd9dc8-a86a-43e9-a5fe-e9e9b3433566
Is it possible to send a message to a teams chat/channel without user interaction?
As per the documentation, application permissions are supported only for migration purposes. For this, your team and channel both must be created in a migrated state. However, you can use this graph API in a delegated context (with signed-in user).
Reference Document: https://learn.microsoft.com/en-us/graph/api/chatmessage-post?view=graph-rest-1.0&tabs=csharp
Using proactive messages you can send a message to a teams chat/channel without user interaction.
Reference Document: https://learn.microsoft.com/en-us/microsoftteams/platform/resources/bot-v3/bot-conversations/bots-conv-proactive

How to access communications API in Microsoft Graph

I want to use the communications API in Microsoft Graph using a simple C# desktop app.
For now, let's say I want to use the GET /communications/calls/{id} request that can only be used via Application Permissions.
From my understanding, only bots can use the communications API.
So I've created a bot in Azure and deployed this code:
https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/csharp_dotnetcore/24.bot-authentication-msgraph
The bot works and I get the user mail etc. but:
The bot uses delegated credentials that are not supported for the Get Call request.
I want to access the API via a C# desktop app using the bot credentials and not using the bot itself(I don't know if this is even possible but logic dictates that it should)
When I try a simple API request using the bot's app credintials (like I would use any other Azure app) I get this response:
{"error":{"code":"UnknownError","message":"","innerError":{"date":"2022-03-31T09:29:44","request-id":"7906abfd-5ba4-439f-939c-42361c2ab255","client-request-id":"7906abfd-5ba4-439f-939c-42361c2ab255"}}}
which is not much help.
I've tried different ways like getting the JWT token for the bot and then using it to get an On-behalf-of provider as shown here:https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS and I get this exception:
MsalUiRequiredException: AADSTS50058: A silent sign-in request was sent but no user is signed in.
The code:
var scopes = new[] { "User.Read" };
var tenantId = "common";
var clientId = "appId";
var clientSecret = "appSecrete";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var oboToken = "JWT token I get form the bot with scope:appId/.default";
var cca = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.Build();
var authProvider = new DelegateAuthenticationProvider(async (request) =>
{
var assertion = new UserAssertion(oboToken);
var result = await cca.AcquireTokenOnBehalfOf(scopes, assertion).ExecuteAsync();
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
var graphClient = new GraphServiceClient(authProvider);
string callId = "callId";
var call = graphClient.Communications.Calls[$"{callId}"].Request().GetAsync();
call.Wait(); //-->here exception
var res = call.Result;
So firstly I want to know is it possible to use the communications API from a desktop app using the bot credentials?
If so then I would really appreciate a good explanation of a step-by-step on how to get the Get Call request to work,
specifically how to set up the bot, how to get the correct Access Token for the Graph API.
If not, I would appreciate a code example of using the Get Call API request from inside the bot.

Send proactive message for Skype using Direct Line API

I am using Direct Line API v4 to send a message to my Web Chat proactively using an existing conversation (by passing the existing conversation ID, saved when the conversation started).
Code:
var client = new DirectLineClient("secreat");
var activity = new Activity();
activity.From = new ChannelAccount("userid");
activity.Type = "resume";
activity.ChannelId = "directline";
activity.Text = "Hi";
activity.Conversation = new ConversationAccount(id: "existingconverstaionid");
var result = client.Conversations.PostActivity("existingconverstaionid", activity);
This code runs fine and I am able to continue with my existing conversation with my Web Chat channel. I would like this same functionality to work for my Skype channel, so I have replaced userid and existingconversationid I received from the Skype conversation, but this does not work...
You can't use the DirectLineClient to broadcast a message to the Skype channel. It is actually quite easy, since you can just use the BotFramework SDK to send a proactive message, as long as you saved the conversation info.
Read more about sending proactive messages using BotFramework v4 or have a look at the example.

Telegram API error USER_DEACTIVATED after authentication

I'm using a simple client for Telegram API on C# using TLSharp library.
var appId = ConfigurationManager.AppSettings["appId"];
var appSecret = ConfigurationManager.AppSettings["appSecret"];
var clientPhone = ConfigurationManager.AppSettings["clientPhone"];
...
var session = new FileSessionStore();
client = new TelegramClient(int.Parse(appId), appSecret, session, clientPhone);
await client.ConnectAsync();
if (!client.IsUserAuthorized())
{
hash = await client.SendCodeRequestAsync(clientPhone);
await client.MakeAuthAsync(clientPhone, hash, code);
}
var state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
Here I'm getting exception USER_DEACTIVATED.
So, I tried to get new clean account (with new phone number), login throgth mobile telegram client, after that login to web version, searched some channels, subscribe, sent some messages. After that I tried to login with my client app and at FIRST request got same error.
This issue started to reproduce just this week. Before that I successfully used several test accounts, getting messaged, worked with media and dialogs, no any deactivate errors.
What I'm doing wrong? What limits or policies was broked my application and does exists any way to restore my app?
UPDATE
Tried to register new application from another account. After that, repeat same actions with new phone number and another PC with another IP address - banned after first request.
What is going on? Why can telegram blocks my accounts?

Persistent authentication across UWP app and Azure Mobile Service

Building on the example here I'm attempting to authenticate an MSA login on the client, and have it authenticate service-side as well. The difference with mine is I'm using the new WebAccount-related API's in Windows 10 instead of the now deprecated Live SDK.
So far I've got:
var provider = await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.microsoft.com", "consumers");
var request = new WebTokenRequest(provider, "service::wl.basic wl.emails::DELEGATION", "none");
var result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
if (result.ResponseStatus == WebTokenRequestStatus.Success)
{
string token = result.ResponseData[0].Token;
//This calls my custom wrappers around the Live REST API v5 and runs successfully with this token
var acc = await LiveApi.GetLiveAccount(token);
var jtoken = new JObject
{
{"authenticationToken", token}
};
try
{
//Shouldn't this work? but raises a 401
await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount, jtoken);
//Alternate method? Also raises a 401
//await App.MobileService.LoginWithMicrosoftAccountAsync(token);
}
}
As I mentioned in the comments, all I get are 401s.
As far as I can tell the application is configured correctly in Microsoft Account dev center:
I'm using the client ID and secret from the same app in the Azure portal.
JWT issuing is not restricted.
Redirect URL is of the format https://{appname}.azurewebsites.net/.auth/login/microsoftaccount/callback
Authentication works fine when I switch to use purely server-side authentication. i.e.
await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
Any ideas? Am I missing something? Any help would be appreciated.
UPDATED:
The token I get back in the WebTokenRequestResult is 877 characters long and does not appear to be in the JWT format, with the dot (.) separators and I'm quite certain that this is the issue. The following error gets logged in service when the client calls the code above:
JWT validation failed: IDX10708: 'System.IdentityModel.Tokens.JwtSecurityTokenHandler' cannot read this string: 'EwCQAq1DBAAUGCCXc8wU/zFu9QnLdZXy+...Zz9TbuxCowNxsEPPOvXwE='.
Application: The string needs to be in compact JSON format, which is of the form: '<Base64UrlEncodedHeader>.<Base64UrlEndcodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>'..
Application: 2015-12-07T17:47:09 PID[5740] Information Sending response: 401.71 Unauthorized
What format is the token currently in? Can it be transformed to a JWT?
Still no closer to a solution, so any help is appreciated.
Anyone feel free to correct me, but it looks like RequestTokenAsync gets you an access token which you can't use to login the backend. You need an authentication token for that, and as far as I can see RequestTokenAsync doesn't get you that.
There's some info here about the tokens.
If people end up here searching for a solution for App Service Mobile, the update to MobileService. Then there is now a solution
The code replicated here is:
async Task<string> GetDataAsync()
{
try
{
return await App.MobileService.InvokeApiAsync<string>("values");
}
catch (MobileServiceInvalidOperationException e)
{
if (e.Response.StatusCode != HttpStatusCode.Unauthorized)
{
throw;
}
}
// Calling /.auth/refresh will update the tokens in the token store
// and will also return a new mobile authentication token.
JObject refreshJson = (JObject)await App.MobileService.InvokeApiAsync(
"/.auth/refresh",
HttpMethod.Get,
null);
string newToken = refreshJson["authenticationToken"].Value<string>();
App.MobileService.CurrentUser.MobileServiceAuthenticationToken
= newToken;
return await App.MobileService.InvokeApiAsync<string>("values");
}
Hope it saves somebody time !

Categories