OfficeDev / Microsoft-Teams-Samples

Welcome to the Microsoft Teams samples repository. Here you will find task-focused samples in C#, JavaScript and TypeScript to help you get started with the Microsoft Teams App!
MIT License
952 stars 754 forks source link

RSC permission in 1:1 conversation with bot #959

Open christopher5106 opened 1 year ago

christopher5106 commented 1 year ago

Hi,

I was implementing the following sample that works well in a team channel as well as in a group chat: https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-rsc/nodeJs/auth.js

I'm using Application RSC permission: ChannelMessage.Read.Group and ChatMessage.Read.Chat. ChatMessage.Read.Chat is working great to retrieve older messages in the group conversation with URL https://graph.microsoft.com/v1.0/chats/{chat-id}/messages

But I have the following graph error when using the same URL in a personal chat:

{'error': {'code': 'Forbidden', 'message': "Missing role permissions on the request. API requires one of 'Chat.Read.WhereInstalled, Chat.ReadWrite.WhereInstalled, ChatMessage.Read.All, Chat.Read.All, Chat.ReadWrite.All, ChatMessage.Read.Chat'. Roles on the request 'Group.Selected'. Resource specific consent grants on the request ''.", 'innerError': {'date': '2023-09-11T12:54:40', 'request-id': 'e84d36de-a0e6-46c4-99f7-2c9406b86674', 'client-request-id': 'e84d36de-a0e6-46c4-99f7-2c9406b86671'}}}

I was wondering where the problem could come from:

1/ if it comes from the conversation ID that I get from Teams that does not correspond to the chat-id I see in the URL in teams web or in microsoft graph when I find my chat with the bot among the chats

2/ if the token "group.selected" is ok and how to change it if necessary

I have no more clue how to deal with that issue. Please help.

microsoft-github-policy-service[bot] commented 1 year ago

Hi @christopher5106! Thank you for bringing this issue to our attention. We will investigate and if we require further information we will reach out in one business day. Please use this link to escalate if you don't get replies.

Best regards, Teams Platform

ChetanSharma-msft commented 1 year ago

Hello @christopher5106 - Thanks for raising your query. We will look into it and let you know the updates.

ChetanSharma-msft commented 1 year ago

Hello @christopher5106 - Looks like "ChatMessage.Read.Chat" permission will not work in 1:1 chat and it is mentioned in the documentation as well: image

Reference doc link: https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent#rsc-permissions-for-a-chat-or-meeting

If you want to List messages in a chat, you can use below Graph API without RSC permissions: List messages in a chat

Could you please check and let me know if you need any further help here.

christopher5106 commented 1 year ago

Ok. I still need little help about the method to call to get user consent on Chat.Read inside my bot ?

christopher5106 commented 1 year ago

And also, please answer the second point: converstion.id I get in the request is not a valid ID for the graph URL /chats/{chat-id}

The ID starts with "a:1AFl..." and is length 131 chars.

The graph error is: Possible error found in URL near: :1AFlDDfaJiHNKHf...

It's not as clear to me how to get the conversation between the bot and me.

Prasad-MSFT commented 1 year ago

In your Teams app manifest, make sure you have specified the correct permission string for personal chat message reading. The permission string for personal chat message reading is 'ChatMessage.Read.Chat'. Ensure that this permission is included in the 'permissions' section of your app manifest.

"permissions": [
  {
    "resource": "ChannelMessage",
    "scope": "Group.Read.All"
  },
  {
    "resource": "ChatMessage",
    "scope": "Chat.Read.Chat"
  }
]

Make sure you have updated the app manifest with the correct permission string and re-install or upgrade your app to apply the changes. After that, you should be able to retrieve messages in a personal chat using the URL https://graph.microsoft.com/v1.0/chats/{chat-id}/messages.

Prasad-MSFT commented 1 year ago

To retrieve the conversation chatId follow below steps:

  1. You must have your app's {teamsAppInstallationId}. If you don't have it, use the following: GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/id eq '{teamsAppId}' The id property of the response is the teamsAppInstallationId.

  2. Make the following request to fetch the chatId: HTTP GET request (permission—TeamsAppInstallation.ReadWriteSelfForUser.All): GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps/{teamsAppInstallationId}/chat The id property of the response is the chatId.

You can also retrieve the chatId with the following request but it requires the broader Chat.Read.All permission:

HTTP GET request (permission—Chat.Read.All): GET https://graph.microsoft.com/v1.0/users/{user-id}/chats?$filter=installedApps/any(a:a/teamsApp/id eq '{teamsAppId}')

Ref: https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/proactive-bots-and-messages/graph-proactive-bots-and-messages?tabs=dotnet#retrieve-the-conversation-chatid

https://learn.microsoft.com/en-us/graph/api/userscopeteamsappinstallation-get-chat?view=graph-rest-1.0&tabs=http

christopher5106 commented 1 year ago

1/ In the GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/id eq '{teamsAppId}' request, I get the fields id, consentedPermissionSet, teamsApp/id, teamsApp/externalId, and when I use id as teamsAppInstallationId in the GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps/{teamsAppInstallationId}/chat request, I get "Possible error found in URL near: =" because this ID finishes with "=". None of the id, teamsApp/id or teamsApp/externalId are working in this request.

2/ With RSC permission ChatMessage.Read.All, am I able to get the teamsAppInstallationId and chatId or what other RSC permission shall I put in the Manifest? Thanks

Prasad-MSFT commented 1 year ago

You need to run this API GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps?$expand=teamsApp and get the id as highlighted below: image

Additionally, you can refer to below document https://learn.microsoft.com/en-gb/microsoftteams/platform/graph-api/rsc/grant-resource-specific-consent#check-your-app-for-added-rsc-permissions-in-a-chat

christopher5106 commented 1 year ago

It's not working:

Capture d’écran 2023-09-13 215847

Capture d’écran 2023-09-13 215928

What is wrong ?

Prasad-MSFT commented 1 year ago

@christopher5106 - We are also observing the same behaviour. In documentation its mentioned to use that id, but on using that it gives away below error: image

So next we opened the conversation with bot in MS Teams and copied the chat-id from browser. image

and ran the following API query and were able to get the chat messages. image

christopher5106 commented 1 year ago

To be sure to understand.

  1. I ask you how to get the chat ID from my bot. You answered by a documentation link List messages in a chat that I know and read 100 times
  2. I told you it's not working. You gave me a procedure to get an ID.
  3. I was not able to make this ID work. You told me to choose the other ID, teamApp/id
  4. I told you this ID is not working. You say to me to copy paste the ID from the browser ?! But how can my bot copy paste the ID from your browser ?!

First, I repeat my question: how to access the chat ID to paste in the URL /chats/{chat-id}/messages ? Second, you have no more option than to give me a correct answer this time I think.

herve-stence commented 1 year ago

Hello, thank you @Prasad-MSFT for all the information provided in this ticket (and thank you Christopher for opening this ticket). I have the same problem and was desperately looking for solutions on the web. So I'm very happy to see a reliable source of information on this subject. I've just opened a github account for that purpose :) But can you clarify how the robot gets this ID ? Like @christopher5106 , I can reproduce the solution on the browser side but not on the robot side. Thanks again

Prasad-MSFT commented 1 year ago

To be sure to understand.

  1. I ask you how to get the chat ID from my bot. You answered by a documentation link List messages in a chat that I know and read 100 times
  2. I told you it's not working. You gave me a procedure to get an ID.
  3. I was not able to make this ID work. You told me to choose the other ID, teamApp/id
  4. I told you this ID is not working. You say to me to copy paste the ID from the browser ?! But how can my bot copy paste the ID from your browser ?!

First, I repeat my question: how to access the chat ID to paste in the URL /chats/{chat-id}/messages ? Second, you have no more option than to give me a correct answer this time I think.

@christopher5106 - Apologies for any inconvenience caused. Earlier we suggested to use teamsAppInstallationId in order to retrieve the conversation chatId according to the official documentation. However, as the id as well as teamApp/id didn't work, we suggested alternative to get the chatId directly from browser (which is something you do not intend to use as in your case you need bot to get that id).

So, if you want to get the id, you can get this from the bot context installationUpdate event while installing the app in personal scope. image

{
    "action": "add",
    "type": "installationUpdate",
    "timestamp": "2023-09-14T13:18:01.14Z",
    "id": "f:6863f3e5-dd69-af99-234e-c623c0f3cdd2",
    "channelId": "msteams",
    "serviceUrl": "https://smba.trafficmanager.net/amer/",
    "from": {
        "id": "29:1GurVOhggttdCEGAZt8SXYhAIWmnd--1IgQ2NY2vXC30K1FI415uXN7a5YmxB9yPawJwBWAn3oL6rNzeImWqiWQ",
        "aadObjectId": "e652dd92-dd63-4fcc-b5b2-2005681e8e9f"
    },
    "conversation": {
        "conversationType": "personal",
        "tenantId": "aa923623-ae61-49ee-b401-81f414b6ad5a",
        "id": "a:1e5Kaun0rWLFm1E0kYKIHeGrP1tLGfl0k9tl7CqIO9END4PgXUIQ9b8sWGfLErh3BgiWXA0p66kt0WTFlpKKybV433XkEco9dgFNRDpKPiflSrVgL85qAEjcwIOVlgDEa"
    },
    "recipient": {
        "id": "28:4acdc558-04cc-49d2-a0c1-4c0f4138a9e9",
        "name": "AzureBotPSD"
    },
    "entities": [
        {
            "locale": "en-GB",
            "type": "clientInfo"
        }
    ],
    "channelData": {
        "settings": {
            "selectedChannel": {
                "id": "19:e652dd92-dd63-4fcc-b5b2-2005681e8e9f_4acdc558-04cc-49d2-a0c1-4c0f4138a9e9@unq.gbl.spaces"
            }
        },
        "tenant": {
            "id": "aa923623-ae61-49ee-b401-81f414b6ad5a"
        },
        "source": {
            "name": "message"
        }
    },
    "locale": "en-GB"
}

We verified this and using this id we were able to get the chat details using Graph API.

cc: @herve-stence

christopher5106 commented 1 year ago

Do we get on_installation_update events very frequently ? Because currently the app has been already installed, how do we trigger an on_installation_update event to get this ID ?

ChetanSharma-msft commented 1 year ago

Hello @christopher5106 - you can uninstall and install the app again just to test it.

ideally you can store the chat I’d in memory while installing the app and later you can use it for further operations.

please let us know if you have any other scenario which can not be implemented using above steps.

christopher5106 commented 1 year ago

Any downtimes or error on our server and all users chat IDs are lost for users that install the app during this time. Not very convenient 😱

christopher5106 commented 1 year ago

Don't you have another method to get this ID?

christopher5106 commented 1 year ago

I'm extremely surprised I'm the first guy to imagine that an user would like to have a chat, ie a personal conversation with a bot

Prasad-MSFT commented 1 year ago

@christopher5106 - installationUpdate event only gets triggered when bot is added or removed from a conversation. In other bot conversation methods, the required id is not available.

christopher5106 commented 1 year ago

So now I have the ID. Please show me how to use MSAL lib to exchange the token for a graph token under the Chat message.Read.Chat RSC permission (no SSO) to read users chat message in Microsoft Graph. I get an invalid grant saying I should have ChaMessage.Read.Chat that my app correctly has. Until now no proof it's working.

Prasad-MSFT commented 1 year ago

@christopher5106 - To use MSAL (Microsoft Authentication Library) to exchange the token for a Graph token under the ChatMessage.Read.Chat RSC permission, you can follow these steps:

  1. Install the MSAL library in your project. You can use the following command to install the MSAL library in your Node.js project:

    npm install msal

  2. Import the necessary modules in your code:

    const msal = require('@azure/msal-node');

  3. Create an instance of the ConfidentialClientApplication class with your application's client ID and client secret:

const config = {
  auth: {
    clientId: 'YOUR_CLIENT_ID',
    clientSecret: 'YOUR_CLIENT_SECRET',
  },
};
const cca = new msal.ConfidentialClientApplication(config);
  1. Acquire a token using the acquireTokenByClientCredential method:
const tokenRequest = {
  scopes: ['https://graph.microsoft.com/.default'],
};
cca
  .acquireTokenByClientCredential(tokenRequest)
  .then((response) => {
    const accessToken = response.accessToken;
    // Use the access token to make Graph API calls
    // For example, you can use the accessToken to call the /me endpoint:
    // GET https://graph.microsoft.com/v1.0/me
  })
  .catch((error) => {
    console.log(error);
  });

In the scopes array, specify the https://graph.microsoft.com/.default scope to request the default Graph API permissions.

Note: Make sure to replace 'YOUR_CLIENT_ID' and 'YOUR_CLIENT_SECRET' with your actual client ID and client secret.

By following these steps, you can use MSAL to exchange the token for a Graph token under the ChatMessage.Read.Chat RSC permission. This will allow you to read users' chat messages in Microsoft Graph without requiring Single Sign-On (SSO).

christopher5106 commented 1 year ago

This is exactly what I'm doing and I'm getting an invalid grand on the chat message url.

Prasad-MSFT commented 1 year ago

Could you please verify these?

  1. Verify the app manifest: Ensure that your app manifest correctly includes the ChatMessage.Read.Chat permission. You can check the manifest file to confirm if the permission is specified as mentioned in the context.

  2. Check the consent process: Make sure that the consent process for your app includes the ChatMessage.Read.Chat permission. During the installation or upgrade process, conversation owners need to grant consent for the app to receive all chat messages. If the consent process is not completed correctly, it can result in an "invalid grant" error.

  3. Validate the token exchange: Double-check the code where you are exchanging the token for a Microsoft Graph token using the MSAL library. Ensure that you are requesting the correct scope (ChatMessage.Read.Chat) and that the token exchange process is implemented correctly.

Here's an example of how you can use the MSAL library to acquire a token for the ChatMessage.Read.Chat permission:

// Create a confidential client application using MSAL
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithClientSecret(clientSecret)
    .WithAuthority(authority)
    .Build();

// Define the required scopes
string[] scopes = new string[] { "ChatMessage.Read.Chat" };

// Acquire a token for the specified scopes
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();

// Use the acquired token to make requests to Microsoft Graph
string accessToken = result.AccessToken;

Make sure to replace clientId, clientSecret, and authority with the appropriate values for your application. Additionally, it is recommended to check the Azure AD logs for more detailed error information.

If you have followed these steps and are still encountering the "invalid grant" error, you can share your manifest file along with your code repo zip, so that we can raise bug from our end.

christopher5106 commented 11 months ago

Hello,

Here is my exact code following your advise:

const msal = require('@azure/msal-node');
const config = {
    auth: {
      clientId: client_id,
      clientSecret: client_secret,
      authority: "https://login.microsoftonline.com/" + tenant
    },
  };
const cca = new msal.ConfidentialClientApplication(config);
const tokenRequest = {
    scopes: ['ChatMessage.Read.Chat'],
};
cca
  .acquireTokenByClientCredential(tokenRequest)
  .then((response) => {
    const accessToken = response.accessToken;
  })
  .catch((error) => {
    console.log(error);
  });

The error message I get

ServerError: invalid_scope: 1002012 - [2023-09-25 19:46:48Z]: AADSTS1002012: The provided value for scope ChatMessage.Read.Chat is not valid. Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).
Trace ID: f83ce916-6b97-49bc-9485-6607d31ec800
Correlation ID: ae5edeae-fc8d-47fb-80d9-3a913f6783aa
Timestamp: 2023-09-25 19:46:48Z - Correlation ID: ae5edeae-fc8d-47fb-80d9-3a913f6783aa - Trace ID: f83ce916-6b97-49bc-9485-6607d31ec800

This code is working with scopes: ['https://graph.microsoft.com/.default'], but in this case when I request the https://graph.microsoft.com/v1.0/chats/{chat_id}/messages, I get: {"error":{"code":"Forbidden","message":"Missing role permissions on the request. API requires one of 'Chat.Read.WhereInstalled, Chat.ReadWrite.WhereInstalled, ChatMessage.Read.All, Chat.Read.All, Chat.ReadWrite.All, ChatMessage.Read.Chat'. Roles on the request 'Group.Selected'. Resource specific consent grants on the request ''.","innerError":{"date":"2023-09-25T19:50:38","request-id":"59068fd7-c380-4f2c-941d-1fee19996227","client-request-id":"59068fd7-c380-4f2c-941d-1fee19996227"}}}

please help urgently but try to understand a bit better my case, because your advises seem generic / copy-paste of Microsoft documentation, not a real help.

christopher5106 commented 11 months ago

This code with the same URL https://graph.microsoft.com/v1.0/chats/{chat_id}/messages is working well to retrieve messages from group chats so I'm a bit suspicious if it's not working for one to one chat messages (with correct ID).

Prasad-MSFT commented 11 months ago

Okay, we will check this internally with engineering team and will update you accordingly.

christopher5106 commented 11 months ago

Do you have any update on that issue ?

Prasad-MSFT commented 11 months ago

Apologies. At the moment, we have not received any updates from the engineering team. However, we are actively communicating with them to stay updated on the progress. As soon as we receive any updates from them, we will notify you in this thread. Thank you!

ChetanSharma-msft commented 10 months ago

Apologies for delay in response. We are actively checking the updates with engineering team and let you know once we get any updates.

ChetanSharma-msft commented 8 months ago

Hello @christopher5106 - Sorry for delay in response. ChatMessage.Read.Chat RSC permission will work if a chat has a meeting or a call associated with it.

Please refer this documentation: https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent#rsc-permissions-for-a-chat-or-meeting

Please let us know if you still need any further help here.

christopher5106 commented 8 months ago

Not every 1:1 chat has a meeting or a call associated with it. How do we deal with general case ?

ChetanSharma-msft commented 8 months ago

Hello @christopher5106 - Could you please confirm below queries: 1) Are you trying to retrieve 1:1 chat related history with bot in personal scope or trying to fetch the other chat's related data (using chat-id value) from your 1:1 conversation?

2) If you try to fetch 1:1 chat related data (Installed bot in personal scope) using RSC permission and chat-id from the same conversation, it is working for you?

christopher5106 commented 8 months ago
  1. retrieve 1:1 chat related history with bot in personal scope
  2. no it's not working, there is a permission error in the case of 1:1 chat, while it's working correctly in channels for example.
ChetanSharma-msft commented 8 months ago

Thanks for the information. We will again test it accordingly and raise a bug if needed.

christopher5106 commented 8 months ago

Thank you

Prasad-MSFT commented 6 months ago

Hi @christopher5106 - We got update from engineering team saying "Currently, the granting of .Chat permissions in personal scope has been locked down to ChatMessageReadReceipt.Read.Chat permission only."