Задача

Надо отправлять сообщения в канал MS Teams из CI/CD через MS Graph API. Тo есть из bash-скрипта.

Что для этого нужно

  • Зарегать приложение на портале https://entra.microsoft.com .
  • Дать приложению права
  • Сгенерировать Authorizaton Code для того, чтобы получить API токен и refresh токен. Authorizaton Code одноразовый, генерируется в интерактивном режиме с аутентификацией пользователя и нужен для получения API-токена (короткоживущий для отправки сообщений) и refresh-токена (живет долго - 90 дней, для получения API-токенов).
  • Получить team id (идентификатор организации в MS Teams), получить channel id.
  • Сверстать сообщение и отправить.

Регистрация приложения

  • Дальше - IdentityApp Registrations
  • В настройках приложения в Overview смотрим Application (client) ID и сохраняем.
  • В Authentication добавляем Redirection URL - http://localhost/myapp
  • В Certificates & Secrets добавляем Secret и сохраняем его ID и Secret
  • В API Permissions жмем Add PermissionMicrosoft Graph и добавляем DelegatedChannelMessage.Send

Немного пояснений:

  • MS Graph API не позволяет отправлять сообщения от имени приложения (то есть использовать статичный секрет для аутентификации). В итоге - используется Delegated привилегия ChannelMessage.Send, то есть приложение от имени пользователя получает токен и отправляет сообщения. Если живой пользователь не должен быть в этой схеме, то MS предлягает использовать служебные учетки - то есть фактически виртуальных бесправных пользователей.

Получение Authorization Code

Это происходит в интерактивном режиме в браузере.
Получаем нужные данные:

  • team_id (или group_id) - напротив любого канала в MS Teams нажимаем три точки и жмем Get link to channel. В этой ссылке будет параметр - groupId. Это он.
  • client_id - это идентификатор приложения Application (client) ID, который мы взяли из Overview
  • Формируем URL:
    https://login.microsoftonline.com/{team_id}/oauth2/v2.0/authorize?client_id={client_id}&response_type=code&response_mode=query&scope=offline_access%20ChannelMessage.Send

  • Вводим этот URL в браузере, нас перекидывает на страницу аутентификации, а после успешной аутентификации - на URL вида

    https://localhost/myapp?code=1......&session_state=0021c0b9-68fb-6cd3-c0ce-49a54fd54a9a

    так вот параметр code в этом URL и есть одноразовый authorization code, пригодный для получения токена.

  • Важно обратить внимание на параметр scope. Он определяет круг привилегий (через пробел), доступный токену, полученному с помощью этого кода. В scope присутствует offline_access, а это значит что с помощью этого authorization code помимо короткоживущего access token можно запросить долгоиграющий refresh token, который можно рассматривать как многоразовый authorization code

Получение Access Token и Refresh Token

Дальше все просто - получаем токены:

MS_GRAPH_API_TOKENS_JSON=`curl -s --location --request POST "https://login.microsoftonline.com/${MS_TENANT}/oauth2/v2.0/token" \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode "client_id=${MS_APPLICATION_ID}" \
    --data-urlencode "code=${AUTHORIZATION_CODE}" \
    --data-urlencode "scope=offline_access ChannelMessage.Send" \
    --data-urlencode "http://localhost/myapp" \
    --data-urlencode "grant_type=authorization_code" 2>/dev/null`
MS_GRAPH_API_TOKEN=`echo ${MS_GRAPH_API_TOKENS_JSON} | awk '{gsub(/\,/,"\n")}1' 2>/dev/null | grep access_token | cut -d':' -f2 | tr -cd '[:alnum:]._-'`
MS_GRAPH_API_REFRESH_TOKEN=`echo ${MS_GRAPH_API_TOKENS_JSON} | awk '{gsub(/\,/,"\n")}1' 2>/dev/null | grep refresh_token | cut -d':' -f2 | tr -cd '[:alnum:]._-'`

Тут MS_TENANT - это все тот же team_id или group_id - Это синонимичные значения в терминологии MS Teams.
Refresh Token - валиден 90 дней, но лучше его периодически обновлять, получая тот же JSON о свежими с токенами уже с помощью имеющегося refresh token:

MS_GRAPH_API_TOKENS_JSON=`curl -s --location --request POST "https://login.microsoftonline.com/${MS_TENANT}/oauth2/v2.0/token" \
        --header 'Content-Type: application/x-www-form-urlencoded' \
        --data-urlencode "client_id=${MS_APPLICATION_ID}" \
        --data-urlencode 'scope=offline_access ChannelMessage.Send' \
        --data-urlencode 'grant_type=refresh_token' \
        --data-urlencode "refresh_token=${MS_GRAPH_API_REFRESH_TOKEN}" 2>/dev/null`
MS_GRAPH_API_TOKEN=`echo ${MS_GRAPH_API_TOKENS_JSON} | awk '{gsub(/\,/,"\n")}1' 2>/dev/null | grep access_token | cut -d':' -f2 | tr -cd '[:alnum:]._-'`
MS_GRAPH_API_REFRESH_TOKEN=`echo ${MS_GRAPH_API_TOKENS_JSON} | awk '{gsub(/\,/,"\n")}1' 2>/dev/null | grep refresh_token | cut -d':' -f2 | tr -cd '[:alnum:]._-'`

Отправка сообщения в канал MS Teams через MS Graph API

MESSAGE="{
  \"body\": {
  \"contentType\": \"html\",
  \"content\": \"Hello World!\"
  }
}"
curl -s -X POST "https://graph.microsoft.com/v1.0/teams/${MS_TEAMS_GROUP_ID}/channels/${MS_TEAMS_CHANNEL_ID}/messages" \
    -H "Authorization: Bearer ${MS_GRAPH_API_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "${MESSAGE}"
Enter your comment. Wiki syntax is allowed:
 
  • devops/message_to_ms_teams_channel_from_bash_with_curl.txt
  • Last modified: 2025/02/25 18:50
  • by admin