Download chatMessage attachments

Copper Contributor



I am using the Graph API to fetch chatMessages of a particular user (using delegated permissions).


I am unable to download attachments of those chatMessages ; a GET query to the contentUrl (, returns "401 UNAUTHORIZED" error.

The contentUrl looks like : https://{devTenant}{userEmail}_onmicrosoft_com/Documents/Microsoft Teams Chat Files/{fileName}

The bearer token that I provide comes from this endpoint : (and works for any other call to the Graph API).


Do you have any idea of how to download attachments ?


Thank you in advance,


17 Replies
we are looking into this, we will get back to you.
we are also seeing the same behavior. We will check internally and get back to you.

@Pierre_Z92 - Engineering team has said that - 


You can use this API - Plug in the sharepoint link from chatMessage attachment and it will get you the download links you need. Additional reference

Thanks for your quick reply.

I have tried this endpoint, and it seems to only work with files belonging to the user from whom my app have delegated permissions.

My case is:
- My app acts on behalf of user A (with delegated permissions)
- User B sends a Teams chatMessage with an attachment to user A
- Attachment is stored in the user B sharepoint/one drive
- Graph API (/shares/{shareIdOrEncodedSharingUrl}) returns an "unauthenticated" error

This exact same endpoint works for files stored in user A one drive.

It looks like I missed a permission but I don't know which one.

My app currently have these delegated permissions:
- Chat.ReadWrite
- Files.ReadWrite.All
- Sites.ReadWrite.All


Can you help me ?

Up ?
We are checking on it internally with the engineering team. We will keep you posted once we have an update.

@Pierre_Z92 - 

Enigineering team has asked for the request-id for the call that fails with unauthenticated? 

Below is the Teams observation -

Unfortunately, property "request-id" is not included in the API response.
The exact returned json is:
"error": {
"code": "unauthenticated",
"message": "The caller is not authenticated."
Users A and B belong to the same tenant/domain.


If I remove the Bearer token when sending request, I get this error message:

"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token is empty.",
"innerError": {
"date": "2022-12-15T13:47:55",
"request-id": "7906a249-f925-4bbf-b4c4-e2cbd1aefd67",
"client-request-id": "7906a249-f925-4bbf-b4c4-e2cbd1aefd67"

Thanks for the details. we will share these details with engineering team and let you know about the updates. Thank you.

@Pierre_Z92 - Engineering team said that the request-id will be in the response headers and the user may need to use something like fiddler to see those values unless the SDK they're using allows them to access them in code. Could you please get request-id using fiddler and share with us.

Request id in header : 81f288a0-a01b-5000-f29d-a610f471198e

@Pierre_Z92 - Engineering team has checked with above request id and has the below observations.

It appears to have been a request made directly to SPO without any authentication. Assuming the user did actually send the request to Microsoft Graph this could indicate that a redirect was returned by Graph that set the location to the SPO endpoint. Most modern code will not reattach the auth when following redirects and so you'd get a 401 response.

I could not find any requests that appeared to redirect though, so we'd need the user to:
1. Tell us if they can see a 3xx response prior to the one that fails to a 401 (it looks like they're using postman so it should hopefully tell them, and if not maybe they can disable auto following of redirects)
2. If they do see a 3xx the request-id and date headers will allow us to drill in

Can you please help sharing the above details?

1. As you advised me, I disabled auto following of redirects on Postman and found out that the endpoint is actually returning a "302 - Found" response.
2. From response headers: request-id "f81f2b83-036e-436b-95db-ba7ccd544d4c" and Date "Fri, 06 Jan 2023 09:27:28 GMT"

Engineering team has said that the 302 is not expected in this case because the request internally failed with an access denied. Team is internally investigating why the incorrect response is being returned. We will get back to you.
Does the engineering team know why access is denied ? Do I miss a permission ?
We are checking with engineering team for updates. We will let you know.

@Pierre_Z92 - Engineering team has said that the reason for the failure is:

The sharing link no longer exists, or you do not have permission to access it.


Team is unable to have a local repro to figure out what's triggering the bogus redirect, but the above is what the user would see if the redirect was not occurring.