Unauthorized Error (401) with Microsoft Graph API: Limitation in Posting Messages to Teams

Emmanuel Moshood 0 Reputation points
2024-11-26T13:48:46.9466667+00:00

I am encountering an issue while attempting to send a reply via the Microsoft Graph API. The operation fails with a 401 error, indicating that message posting in application-only context is restricted to import purposes.

Granted API Permissions and types:

  • ChannelMessage.Read.All Application
  • ChannelMessage.ReadWrite Delegated
  • ChannelMessage.Send Delegated
  • Chat.ReadWrite.All Application
  • Group.ReadWrite.All Application
  • Teamwork.Migrate.All Application
  • User.Read Delegated

python code:

  • Generates access token
  • use access token to post message in team channel or reply to existing message
import msal
import constants
import requests

def generate_access_token(app_id, client_secret, authority, scopes):
    # Create a ConfidentialClientApplication with client credentials
    client = msal.ConfidentialClientApplication(
        client_id=app_id,
        client_credential=client_secret,
        authority=authority
    )

    # Acquire token for client using client credentials
    token_response = client.acquire_token_for_client(scopes=scopes)

    if 'access_token' in token_response:
        # print(f" access_token = {token_response['access_token']}")
        return token_response['access_token']
    else:
        print("Error acquiring token:", token_response.get("error_description"))
        return None


def test_post_message_to_channel( app_id, client_secret, authority, scopes, team_id, channel_id, message_content):
    access_token = generate_access_token(app_id, client_secret, authority, scopes)

    url = f"https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages"
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        "body": {
            "content": message_content
        }
    }
    
    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 201:
        print("Message posted successfully!")
        return response.json()
    else:
        print("Failed to post message:", response.status_code, response.text)
        return None


def test_reply_message_to_channel(app_id, client_secret, authority, scopes, team_id, channel_id, message_id, reply_content):
    # Get access token
    access_token = generate_access_token(app_id, client_secret, authority, scopes)
    # if 'access_token' not in token_response:
    #     print("Error acquiring token:", token_response.get("error_description"))
    #     return
    
    # Define the API endpoint and reply payload
    url = f'https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages/{message_id}/replies'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        "body": {
            "content": reply_content
        }
    }

    # Send the reply to the existing post
    response = requests.post(url, headers=headers, json=payload)

    # Check if the reply was sent successfully
    if response.status_code == 201:
        print("Reply sent successfully!")
    else:
        print("Failed to send reply:", response.status_code, response.text)



# Usage
if __name__ == "__main__":
       
    test_reply_message_to_channel( 
        app_id=constants.APP_ID, 
        client_secret=constants.CLIENT_SECRET, 
        authority =constants. AUTHORITY, 
        scopes=constants.SCOPES, 
        team_id=constants.TEAM_ID, 
        channel_id=constants.CHANNEL_ID, 
        message_id=constants.MESSAGE_ID,
        reply_content=constants.MESSAGE_CONTENT
        )



Error Message Received:


{
  "error": {
    "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.",
    "innerError": {
      "date": "2024-11-26T12:10:19",
      "request-id": "da3b9b53-43d3-407a-9608-9797217e4909",
      "client-request-id": "da3b9b53-43d3-407a-9608-9797217e4909"
    }
  }
}

I'm afraid we can't use client-credential-flow here for sending message to channel. Or is there another way around this that does not require user sign in.

Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
12,484 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. CarlZhao-MSFT 43,176 Reputation points
    2024-11-27T01:55:51.6966667+00:00

    Hi @Emmanuel Moshood

    As the error message says, application permissions only support importing third-party platform messages and require your team and channel to be created in the migration state.

    To send messages, you must use a delegated context.

    User's image

    Hope this helps.

    If the reply is helpful, please click Accept Answer and kindly upvote it. If you have additional questions about this answer, please click Comment.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.