結論から言うと、Microsoft Teamsのチャットを人へ案内するだけなら、対象メッセージのMore options(その他のオプション)からCopy link(リンクをコピー)を使い、URLをそのまま共有するのが最も安全です。アプリ開発でチャットIDが必要ならMicrosoft GraphのGET /me/chatsなど公開APIから取得し、Botでは受信Activityのconversation.idをそのBot会話の文脈で使います。ブラウザー開発者ツールのNetworkから内部通信やトークンを探す方法は使いません。
Teamsでは、チャットID、チャネルID、メッセージID、会議のonlineMeeting ID、会議チャットのthreadId、Botのconversation IDが似た場面に登場します。文字列の末尾を見て推測せず、どのAPIまたはUIから取得し、どのリソースに使うIDかをセットで管理してください。IDを知ってもアクセス権は得られず、ユーザーまたはアプリには対象会話へアクセスする正当な権限が必要です。
用途別の判断表
| 目的 | 使う方法 | 必要な識別子 | 避ける方法 |
|---|---|---|---|
| 人を特定メッセージへ案内 | TeamsのCopy link | コピー済みの公式リンク | ブラウザーのアドレスバーURLを加工 |
| 人を特定チャットへ案内 | 公式チャットディープリンク | chatId | 接尾辞を手作業で変更 |
| 参加者を指定してチャットを開く | /l/chat/0/0?tenantId=<tenantId>&users=... | 参加者のUPN | 勝手にメッセージを自動送信する仕組み |
| アプリで自分のチャットを列挙 | Microsoft Graph List chats | chatリソースのid | Power Automate内部JSONやDOMを契約として利用 |
| Botが受信会話へ応答 | 受信Activity | conversation.id | Graph chat IDと常に同一と仮定 |
| 会議チャットを関連付け | onlineMeetingのchatInfo | threadId | onlineMeeting.idと取り違える |
| チャネルの返信を扱う | Graph chatMessage | channelId、messageId、replyToId | chatIdだけで全種類を表す |
識別子の違いを先に理解する
| 識別子 | 何を表すか | 代表的な取得元 | 注意点 |
|---|---|---|---|
| chat.id | 1対1またはグループチャットのchatリソース | GraphのList chats、Get chat、TeamsのCopy link | 不透明な文字列として扱う |
| channelId | チーム内チャネル | Teamsのチャネルリンク、Graphのchannel | teamIdまたはgroupIdと別 |
| chatMessage.id | 個々のメッセージ | GraphのchatMessage応答、Copy link | chatIdやchannelIdと別 |
| replyToId | チャネルスレッドのルートメッセージとの関係 | GraphのchatMessage | 返信そのもののidとは別 |
| onlineMeeting.id | Graphのオンライン会議リソース | onlineMeeting API | 会議チャットのthreadIdと別 |
| chatInfo.threadId | 会議に関連するTeamsスレッド | onlineMeeting.chatInfo | onlineMeeting.idの代用にしない |
| Bot conversation.id | Botが受信した会話コンテキスト | Bot Framework Activity | Graphのchat.idと形式が同じとは限らない |
| tenantId | Microsoft Entraテナント | Teamsリンク、認証コンテキスト | チャットIDでもアクセス権でもない |
多くのTeams会話識別子は19:で始まりますが、それだけで同じリソースだとは言えません。公式ディープリンク資料も、個人またはグループチャット、チャネル会話、Botとの1対1などで異なる形式を示しています。アプリでは接尾辞を分解して用途を判断せず、GraphのchatType、呼び出したAPIパス、Teamsのコンテキストなど構造化された情報を使います。
方法1:TeamsのCopy linkを使う
利用者がチャットIDそのものを保存する必要はなく、同僚を対象メッセージへ案内したいだけならCopy linkが第一選択です。Microsoftの公式資料では、チャット内のメッセージへポインターを合わせ、More options、Copy linkを選ぶと、コピーしたリンクにチャットIDが含まれると説明されています。
- Teamsで対象のチャットを開く。
- 案内したいメッセージへポインターを合わせる。
- More optionsまたは三点メニューを選ぶ。
- Copy linkを選ぶ。
- 共有先の利用者がそのチャットのメンバーで、対象テナントへアクセスできるか確認する。
- リンクをそのまま共有し、受信者が正しい会話とメッセージへ移動できるか確認する。
新しいTeamsでは、ブラウザーのアドレスバーからコピーしたTeams URLがディープリンクとして動かない場合があるとMicrosoftが明記しています。Teamsが正しく処理するディープリンクはhttps://teams.microsoft.com/l/で始まる公式形式を使います。アドレスバーの長いURLから一部を切り出し、独自形式を作らないでください。
リンクを受け取った人が会話へ参加していない場合、リンクを知っていても内容を閲覧できるとは限りません。リンクは認可を付与しません。アクセス要求を回避するためにスクリーンショットやメッセージ本文を別経路へ無断転載せず、会話の所有者と組織ポリシーに従ってメンバーシップまたは共有方法を見直します。
方法2:公式のチャット用ディープリンクを作る
既存チャットを開く
特定の既存チャットへ移動する公式形式は次のとおりです。CHAT_IDには、Copy link、Graph、正規のTeamsコンテキストから取得したチャットIDをURLエンコードして入れます。これは構文を示すメタ変数であり、任意の文字列を作る欄ではありません。
https://teams.microsoft.com/l/chat/CHAT_ID/conversations
チャットIDは通常19:で始まりますが、コロン、アットマーク、その他の予約文字を含むため、URLの場所に応じて正しくエンコードします。IDを一度デコードし、さらに別のライブラリが再エンコードする二重処理にも注意します。動作しないからといって@thread.v2などの接尾辞を別の値へ書き換えないでください。
参加者を指定してチャットを開く
チャットIDを持っていなくても、参加者を指定して既存または新規チャットを開く公式ディープリンクがあります。次はMicrosoftのドキュメントで示される構造に沿った例です。
https://teams.microsoft.com/l/chat/0/0?tenantId=aaaabbbb-0000-cccc-1111-dddd2222eeee&users=joe%40contoso.com,bob%40contoso.com&topicName=Project%20Review&message=%E7%A2%BA%E8%AA%8D%E3%82%92%E3%81%8A%E9%A1%98%E3%81%84%E3%81%97%E3%81%BE%E3%81%99
現行形式ではtenantIdを含めます。例のUUIDは説明用で、実装では対象テナントIDを検証してクエリ値としてエンコードします。usersは各UPNを個別にURLエンコードしてからカンマで連結し、topicNameとmessageも必ずURLエンコードします。操作する本人は参加者へ含まれます。topicNameは3人以上のチャット名として任意、messageは入力欄へ入る任意文です。messageは自動送信されないため、利用者が確認して送信します。
URLはブラウザー履歴、メールゲートウェイ、チャット、ログへ残るため、messageへパスワード、アクセストークン、個人情報、未公開情報を入れないでください。実在するtenantIdと参加者UPNも組織情報・個人情報になり得ます。公開Webページへ実値入りリンクを置かず、アクセス制御された業務システムで必要な時だけ生成し、ログではtenantId、UPN、messageをマスクします。
方法3:Microsoft Graphでchat IDを取得する
アプリが認可された範囲でチャットを列挙する場合はMicrosoft Graphを使います。委任アクセスとアプリ専用アクセスでは、エンドポイント、最小権限、同意の主体が異なります。この記事ではアクセストークンや取得済みヘッダーを表示せず、SDKとMicrosoft Authentication Library(MSAL)などの認証ライブラリにトークン処理を任せます。
委任アクセス:サインイン中の職場・学校アカウント
GET https://graph.microsoft.com/v1.0/me/chats?$expand=members
サインイン中の職場または学校アカウントが自分のチャット基本情報を読む場合は/me/chatsを使い、最小の委任権限Chat.ReadBasicから検討します。個人Microsoftアカウント(MSA)はList chatsの委任アクセスをサポートしません。メッセージ本文の読取や書込が要件にないなら、Chat.Read、Chat.ReadWriteへ広げません。
アプリ専用アクセス:対象ユーザーを明示する
GET https://graph.microsoft.com/v1.0/users/{user-id-or-user-principal-name}/chats?$expand=members
アプリケーション権限にはサインイン中の利用者がいないため/meを使いません。対象ユーザーを/users/{user-id-or-user-principal-name}/chatsで明示し、基本情報だけなら最小のアプリケーション権限Chat.ReadBasic.Allから検討します。アプリ専用権限には管理者同意が必要で、アプリ所有者、証明書・資格情報、利用対象、保持期間を定め、定期的なアクセスレビューを行います。本文の読取や書込が不要ならChat.Read.All、Chat.ReadWrite.Allへ広げません。
参加者の展開上限とページング
List chatsの応答でmembersとlastMessagePreviewを使うには、それぞれ$expandで明示的に要求します。$expand=membersで返るメンバーは最大25件で、25人を超えるチャットの完全名簿を保証しません。また、チャット一覧が複数ページなら応答の@odata.nextLinkをそのまま使い、値がなくなるまで全ページを追います。$topを指定しただけで全チャットを取得できたと判断しません。
GET https://graph.microsoft.com/v1.0/chats/{chat-id}/members
25人を超えるチャットを含め完全な参加者を確認する場合は、List members of a chatを別に呼び出します。最小権限は委任の職場・学校アカウントでChat.ReadBasic、アプリケーションでChatMember.Read.Allです。個人Microsoftアカウントは未対応で、このAPIは応答をカスタマイズするODataクエリをサポートしません。List chatsの25件展開を完全名簿として保存しないでください。
応答の各chatリソースにあるidをチャットIDとして使います。chatType、topic、展開した参加者、最終更新などの構造化情報で目的のチャットを識別します。表示名だけで選ぶと同名グループチャットを取り違えます。選択画面に必要な確認情報だけを示し、ID全文を一般画面へ露出させる必要はありません。
404は常に「IDが間違い」とは限らず、別テナント、削除済み、権限上見えない、APIパスの取り違えも考えます。403は権限、同意、ユーザーのアクセス、アプリの対象範囲を確認します。エラーを消すために権限を広げず、委任かアプリ専用か、基本情報だけかを先に見直します。
トークンを記事・URL・ログへ出さない
アクセストークンはAPIへのアクセスを許可する機密資格情報です。Microsoftは機密性が高く、正しく扱わなければセキュリティリスクになると説明しています。トークンは不透明な文字列として扱い、クライアント側で内容を解析して認可判断をしません。Graphへの送信は認証ライブラリとHTTPSを通じて行い、URLクエリへ付けません。
- 実トークンをコード例、スクリーンショット、チケット、Teams投稿、ブラウザー履歴へ残さない。
- ブラウザー開発者ツールのNetwork画面をトークンやCookieが見える状態で共有しない。
- ソース管理へクライアントシークレット、証明書秘密鍵、更新トークンをコミットしない。
- 必要最小権限、短い保持期間、アクセス制御されたトークンキャッシュを使う。
- 漏えいした可能性がある場合は、文字列を黒塗りするだけで終えず、アプリ所有者とセキュリティ担当へ連絡して失効・資格情報更新を行う。
方法4:Botの受信Activityからconversation.idを取得する
Teams Botは、Teamsから受信したActivityの会話コンテキストを使って応答します。MicrosoftのActivity handlers and bot logicに沿って、受信ActivityをSDKのActivity handlerで処理します。conversation.idはそのBotが受け取った会話文脈の識別子として扱い、クライアント画面のDOMやNetworkから探しません。必要な会話参照だけをアクセス制御されたストレージへ保存します。
ただし、Botのconversation.idをGraphのchat.idと常に同じものとして扱わないでください。Microsoftのディープリンク資料では、Botとの1対1チャットの受信ペイロードにa:で始まるconversation IDが含まれる場合があると説明されています。Bot Frameworkで返信する識別子と、Graphのchat APIへ渡す識別子は、利用するSDKとAPIの契約に従って分けます。
- 受信ActivityがTeamsチャネルから正規に到着したことをBot Frameworkのアダプターで検証する。
- Activityのconversation、tenant、channelDataなど必要なコンテキストをSDKの型から読む。
- conversation.idを、そのBot会話へ返信または継続する目的で保存する。
- Graphのchat APIへ流用する必要がある場合は、公式に対応する変換・取得方法があるかを確認する。
- ログではID、UPN、tenantId、メッセージ本文を必要最小限にし、保持期間と閲覧権限を設定する。
Botが15秒を超えてActivityを処理すると、Teamsが再試行し、重複リクエストを受ける可能性があると公式資料にあります。ID取得とメッセージ送信を組み合わせる実装では、Activity IDなどで重複処理を防ぎます。「同じconversation.idだから一度しか届かない」と仮定しないでください。
会議IDと会議チャットのthreadIdを区別する
Microsoft GraphのonlineMeetingリソースには会議自体を識別するidがあります。一方、会議に関連するTeamsの会話情報はchatInfoにあり、そのthreadIdがTeamsスレッドの識別子です。会議参加URL、会議ID、会議コード、chatInfo.threadIdは用途が異なります。
| 値 | 用途 | 誤用した場合 |
|---|---|---|
| onlineMeeting.id | Graphでオンライン会議リソースを取得・管理 | チャットAPIへ渡しても同じ会話を指すとは限らない |
| chatInfo.threadId | 会議に関連するTeamsスレッド | 会議リソースIDの代わりにはならない |
| joinWebUrl | 利用者が会議へ参加するURL | APIの主キーやチャットIDとして保存しない |
| chatInfo.messageId | チャネルに関連する会議情報のメッセージ | threadIdと同一ではない |
| chatInfo.replyChainMessageId | 返信チェーンとの関連 | 個々の返信メッセージIDと混同しない |
予定表イベントから会議を取得する、joinWebUrlからonlineMeetingを取得する、会議チャットへアクセスする操作では、それぞれ対応APIと権限が異なります。URL文字列を分解してchatIdを推測せず、Graphが返す構造化フィールドを使います。会議終了後も保持やアクセス要件が変わるため、IDを永久保存する前にデータ保持方針を確認します。
チャネルとメッセージのIDを区別する
チームのチャネル会話は、1対1・グループチャットとはAPIパスが異なります。チャネルのルート投稿と返信ではchatMessage.idとreplyToIdを使います。replyToIdがルートメッセージを示し、返信自身にも別のidがあります。channelIdはチャネル、teamIdまたはMicrosoft 365 groupIdはチームやグループを示します。
特定のチャネル会話へ移動するディープリンクではchannelId、messageId、tenantId、groupId、parentMessageIdなど複数のパラメーターが使われます。chatIdだけを抜き出して全ケースに使う設計にしないでください。Teams UIのリンクを共有する用途なら、公式のCopy linkをそのまま使うことで、必要なパラメーターを手作業で組み直す誤りを減らせます。
失敗したときの診断表
| 症状 | 原因候補 | 確認すること | 対処 |
|---|---|---|---|
| リンクがTeamsで開かない | アドレスバーURL、形式不正、エンコード不正 | https://teams.microsoft.com/l/で始まるか | Copy linkまたは公式形式で作り直す |
| 別のチャットが開く | 参加者、chatId、テナントの取り違え | 取得元、chatType、参加者 | 表示名だけで選ばずGraph応答を再照合 |
| 404になる | ID誤り、別テナント、削除、権限上不可視 | APIパス、tenant、対象存在、認可 | ID接尾辞を変更せず、正規取得元から再取得 |
| 403になる | 権限不足、同意不足、ユーザーが非メンバー | 委任権限、アプリ権限、同意、所属 | 最小権限のまま必要な承認とアクセスを整える |
| メッセージへ移動しない | messageId、context、channel/chatの取り違え | Copy linkの完全なURL | パスとクエリを省略せず使う |
| 新規チャットで送信されない | 仕様どおり入力欄へ入るだけ | compose欄の内容 | 利用者が確認して送信する |
| BotでID形式が違う | Bot conversation IDとGraph chat IDの違い | 受信Activityと使用API | 各SDKの契約に従い別フィールドとして扱う |
| 会議チャットに届かない | onlineMeeting.idとthreadIdの混同 | onlineMeeting.chatInfo | Graph応答のthreadIdを用途どおり使う |
| Graph呼び出し後に情報漏えい | ログや画面へトークンを出した | ログ、チケット、共有画面、資格情報 | セキュリティ担当へ報告し、トークン・資格情報を失効 |
エラーを直すために権限を最大化するのは危険です。まず、利用者が対象会話へアクセスできるか、アプリの目的が基本情報の読取か本文の読取・送信か、委任権限で足りるかを確認します。IDは識別子であり、認可ではありません。403と404を見分けにくいAPIもあるため、監査ログとアプリ同意を管理者が確認します。
ロールバックと誤共有への対応
- 誤リンク:配布した文書、Teams投稿、アプリ設定から誤ったリンクを削除し、Copy linkで取得した正しいリンクへ置き換える。
- 誤った会話の識別子:キャッシュやデータベースから該当レコードを無効化し、正規APIから再取得する。接尾辞を書き換えて修正しない。
- 過剰権限:Microsoft Entraのアプリ同意を見直し、不要なGraph権限を削除して再認証する。
- 実トークンの露出:単なる記事修正ではなく資格情報漏えいとして報告し、セッション、アプリ資格情報、秘密鍵を必要に応じて失効・更新する。
- ログ過多:ID、UPN、tenantId、本文、トークンをマスクまたは削除し、保持期間と閲覧者を最小化する。
- 誤送信:メッセージ削除だけで終えず、受信者、監査、データ所有者、コンプライアンス手順を確認する。
チャットID自体はパスワードではありませんが、会話の存在、参加関係、テナント情報を推測させる場合があります。不要な公開を避け、リンク先へアクセスできる人だけに共有します。アクセストークン、更新トークン、Cookie、クライアントシークレットはIDよりはるかに重大な秘密です。画面録画やサポート提出物へ含めないでください。
よくある質問
チャットIDは必ず19:で始まりますか?
Teamsのチャット用ディープリンクでは通常19:で始まる形式が案内されていますが、Botの受信conversation IDなど別コンテキストでは異なる形式があります。先頭や末尾だけで種類を判断せず、取得元と利用APIを記録します。
Copy linkのURLからIDをデコードして保存すべきですか?
人へリンクを共有するだけなら抽出不要です。URLをそのまま使います。アプリがIDを必要とするなら、Graphなど公開APIの構造化フィールドから取得する方が安全です。デコードと再エンコードを繰り返すとリンクを壊すことがあります。
Power Automateのコードビューからrecipientを取れますか?
コネクタ内部のパラメーター形状を汎用API契約として使う方法は掲載しません。TeamsのCopy link、Microsoft Graphのchatリソース、Botの受信Activityなど、Microsoftが公開している契約から取得してください。
開発者ツールのNetworkで探す方が確実ですか?
いいえ。内部実装に依存し、トークン、Cookie、メッセージ本文、テナント情報を露出する危険があります。公式の取得方法ではありません。Copy link、Graph、Bot Framework、onlineMeeting.chatInfoを用途別に使います。
チャットIDがあれば誰でも投稿できますか?
できません。IDは識別子であり、アクセス権を付与しません。ユーザーまたはアプリには対象チャットへのアクセス、必要なGraph権限、同意、メンバーシップなどが必要です。IDを得るために権限を広げるのではなく、業務目的から最小権限を選びます。
onlineMeeting.idをチャットIDとして使えますか?
使い分けが必要です。onlineMeeting.idは会議リソース、会議に関連するTeamsスレッドはonlineMeetingのchatInfo.threadIdです。joinWebUrlも別です。Graph応答のフィールド名と用途を保ったまま保存します。
Microsoft公式資料
- Configure deep links
- Deep link to Teams chat
- List chats
- List members of a chat
- chat resource type
- chatMessage resource type
- onlineMeeting resource type
- chatInfo resource type
- Access tokens in the Microsoft identity platform
- Activity handlers and bot logic
まとめ
Teamsの参加者ディープリンクはtenantIdを含む現行形式を使い、users、topicName、messageを一貫してURLエンコードします。Graphは、委任の職場・学校アカウントなら/me/chatsとChat.ReadBasic、アプリ専用なら/users/{id-or-UPN}/chatsとChat.ReadBasic.Allから検討し、個人MSAや不要な本文読取・書込権限へ広げません。参加者は$expand=membersだけでは最大25件なので、完全確認にはList chat membersを使い、一覧の@odata.nextLinkを最後まで追います。Botのconversation.idをGraph chat.idと同一保証せず、Activity handlerの再試行と重複を処理してください。

コメント