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
Related
i have created secret key from azure and use in code it's working perfectly fine but when i use secret key create from my gmail account i do not receive any email.
I am using the same code for both send grid api keys one from azure sendgrid account another from my direct sendgrid account but from azure sendgrid account emails are delivering without any error and in sendgrid activities tab also there is recent record but form my direct sendgrid account emails are not delivering and there is not recent record in activity tab.
static async Task Execute()
{
dynamic client = new SendGridClient("SG.Ge6udT3CQtKCuGIxhGwqkg.***************-B--zeJXJKnlomAzB2XzQ");
var msg = new SendGridMessage();
//noreply#teamx.ae
msg.SetFrom(new EmailAddress("360loyalofficial#gmail.com", "Teamx | Services"));
var recipients = new List<EmailAddress>
{
new EmailAddress("nauman.nasir138#gmail.com")
};
msg.AddTos(recipients);
msg.SetSubject("Test");
msg.AddContent(MimeType.Text, "test");
msg.AddContent(MimeType.Html, "test");
var response = await client.SendEmailAsync(msg);
}
Your messages won't be delivered because you don't own or control the gmail.com domain.
More details can be found here:
https://sendgrid.com/blog/dont-send-email-from-domains-you-dont-control/
but essentially it's a security feature to stop scammers and your message won't be delivered.
I have a Bot Framework V3 SDK implementation (working fine) that can initiate a 1:1 private chat with any user in a specific Team using a Microsoft Teams Bot (installed on the same team).
I am having problems trying to migrate it to the V4 SDK.
I read on various articles and other questions that it's not possible to do it unless the user contacts the the bot first (to avoid spamming to users), but this is not true with the V3 version and not an option for the functionality that I need.
The original solution uses the "CreateOrGetDirectConversation" extension method from the Microsoft.Bot.Connector.Teams assembly, but it's not available in the V4 version of the assembly.
I tried using the CreateDirectConversation/CreateDirectConversationAsync methods but with no success (they always result in "Bad Request" errors).
This is the code actually working using the V3 libraries:
// Create 1:1 conversation
var conversation = connectorClient.Conversations.CreateOrGetDirectConversation(botAccount, user, tenantId);
// Send message to the user
var message = Activity.CreateMessageActivity();
message.Type = ActivityTypes.Message;
message.Text = "My message";
connectorClient.Conversations.SendToConversation((Activity)message, conversation.Id);
And I am finding it very hard to migrate. Am I missing something?
Per the docs, Proactive messaging for bots:
Bots can create new conversations with an individual Microsoft Teams user as long as your bot has user information obtained through previous addition in a personal, groupChat or team scope. This information enables your bot to proactively notify them. For instance, if your bot was added to a team, it could query the team roster and send users individual messages in personal chats, or a user could #mention another user to trigger the bot to send that user a direct message.
Note: The Microsoft.Bot.Builder.Teams extension is still in Prerelease for V4, which is why samples and code are kind of hard to find for it.
Adding the Middleware
In Startup.cs:
var credentials = new SimpleCredentialProvider(Configuration["MicrosoftAppId"], Configuration["MicrosoftAppPassword"]);
services.AddSingleton(credentials);
[...]
services.AddBot<YourBot>(options =>
{
options.CredentialProvider = credentials;
options.Middleware.Add(
new TeamsMiddleware(
new ConfigurationCredentialProvider(this.Configuration)));
[...]
Prepping Your Bot
In your main <YourBot>.cs:
private readonly SimpleCredentialProvider _credentialProvider;
[...]
public <YourBot>(ConversationState conversationState, SimpleCredentialProvider CredentialProvider)
{
_credentialProvider = CredentialProvider;
[...]
Sending the Message
var teamConversationData = turnContext.Activity.GetChannelData<TeamsChannelData>();
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), _credentialProvider.AppId, _credentialProvider.Password);
var userId = <UserIdToSendTo>;
var tenantId = teamConversationData.Tenant.Id;
var parameters = new ConversationParameters
{
Members = new[] { new ChannelAccount(userId) },
ChannelData = new TeamsChannelData
{
Tenant = new TenantInfo(tenantId),
},
};
var conversationResource = await connectorClient.Conversations.CreateConversationAsync(parameters);
var message = Activity.CreateMessageActivity();
message.Text = "This is a proactive message.";
await connectorClient.Conversations.SendToConversationAsync(conversationResource.Id, (Activity)message);
Note: If you need to get user ID's, you can use:
var members = (await turnContext.TurnState.Get<IConnectorClient>().Conversations.GetConversationMembersAsync(
turnContext.Activity.GetChannelData<TeamsChannelData>().Team.Id).ConfigureAwait(false)).ToList();
Also, I didn't need this in my testing, but if you get 401 errors, you may need to trust the Teams ServiceUrl:
MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl);
Resources
Teams Extension on MyGet
Teams Extension MyGet Package Repo
Samples using the extension
Proactive Teams Sample
Useful, unofficial blog post
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);
}
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?
I downloaded the example below to get an access token from MS Graph and it worked fine. Now I changed the code to get a token from a custom web API. On apps.dev.microsoft.com I registered a client application and an the API.
Client and server registration in AD
private static async Task<AuthenticationResult> GetToken()
{
const string clientId = "185adc28-7e72-4f07-a052-651755513825";
var clientApp = new PublicClientApplication(clientId);
AuthenticationResult result = null;
string[] scopes = new string[] { "api://f69953b0-2d7f-4523-a8df-01f216b55200/Test" };
try
{
result = await clientApp.AcquireTokenAsync(scopes, "", UIBehavior.SelectAccount, string.Empty);
}
catch (Exception x)
{
if (x.Message == "User canceled authentication")
{
}
return null;
}
return result;
}
When I run the code I login to AD via the dialog en get the following exception in the debugger:
Error: Invalid client Message = "AADSTS65005: The application
'CoreWebAPIAzureADClient' asked for scope 'offline_access' that
doesn't exist on the resource. Contact the app vendor.\r\nTrace ID:
56a4b5ad-8ca1-4c41-b961-c74d84911300\r\nCorrelation ID:
a4350378-b802-4364-8464-c6fdf105cbf1\r...
Error message
Help appreciated trying for days...
For anyone still striking this problem, please read this:
https://www.andrew-best.com/posts/please-sir-can-i-have-some-auth/
You'll feel better after this guy reflects all of your frustrations, except that he works it out...
If using adal.js, for your scope you need to use
const tokenRequest = {
scopes: ["https://management.azure.com/user_impersonation"]
};
I spent a week using
const tokenRequest = {
scopes: ["user_impersonation"]
};
.. since that is the format that the graph API scopes took
As of today, the V2 Endpoint does not support API access other than the Microsoft Graph. See the limitations of the V2 app model here.
Standalone Web APIs
You can use the v2.0 endpoint to build a Web API that is secured with
OAuth 2.0. However, that Web API can receive tokens only from an
application that has the same Application ID. You cannot access a Web
API from a client that has a different Application ID. The client
won't be able to request or obtain permissions to your Web API.
For the specific scenario that you are trying to accomplish, you need to use the V1 App Model (register apps on https://portal.azure.com).
In the very near future, V2 apps will be enabled to call other APIs other than Microsoft Graph, so your scenario will be supported, but that is just not the case today. You should keep an eye out on our documentation for this update.
In your (server) application registration in AAD, you need to specify your scopes in the oauth2Permissions element.
You may already have a user_impersonation scope set. Copy that as a baseline, give it a unique GUID and value, and then AAD will let your client request an access token with your new scope.