Experience Cloud「チャット窓」の会話相手をAgentforceに安全に伝えるには

みなさんこんにちは。エンジニアの佐藤です。今回は前回に引き続き、Experience Cloudの「チャット窓」こと、組み込みメッセージングコンポーネントのお話です。

AIチャットボットにユーザーが期待する機能の一つに、パーソナライズがあります。AIチャットボットが自分のことを覚えていてくれて、気を利かせた応答をしてくれたら、きっと便利なことでしょう。Experience Cloudでページの内容にログインユーザーの情報を織り込むことは容易にできます。ぜひAIチャットボットにも同様にユーザー情報を注入したいものです。

とは言え、ここで問題になるのは、ユーザーをどうやって「安全に」特定するかです。会話の中で「私は佐藤です。」と言われたからといって、AIチャットボットは「佐藤さんですね。」と返すわけにはいきません。別人がなりすましているかもしれないからです。

Experience Cloudサイトへのログインユーザーを、安全に(なりすましができない形で)Agentforceエージェントに知らせる手段はないものでしょうか。Salesforceメッセージングにはこのための機能が用意されており、「ユーザー検証」と呼ばれています。以下にこの設定方法について解説したいと思います。

「簡単、安全、確実」な方法が、実はある

そうなのです。端的に言えば、以下のこれだけです。

  • 拡張チャットメッセージングで「メッセージングのユーザー検証」を有効にする。
  • Experience Cloudサイト(ユーザー認証を要するもの)に組み込みメッセージングコンポーネントを配置する。
  • 組み込みメッセージングコンポーネントの「ログイン情報ベースのユーザー検証の追加」を有効にする。

順番に見ていきましょう。まず、一昨年の弊社ブログ「Service Agent を Web ページから利用する」の手順に従って以下を準備します。

  • 拡張チャットメッセージング
  • 組み込みサービスリリース
  • キュー

なお、オムニチャネルメッセージングフローについては、最近のアップデートで不要になり、拡張チャットメッセージングを直接Agentforceエージェントに接続できるようになりました。以下は拡張チャットメッセージングの該当部分です。

ここで一つ、重大な制約があります。本校執筆時点では、このユーザー検証機能は組み込みサービスリリースV1のみ対応しており、前回ブログでUI拡張をご説明したV2は対応していません。(ぜひ早期に対応してもらいたいものです。)

拡張チャットメッセージングの設定(下図参照、開き方注意)では、「ユーザー検証を追加」をチェックしましょう。

次にExperience Cloudサイトに組み込みメッセージングコンポーネントを配置したら、「ログイン情報ベースのユーザー検証の追加」をチェックします。

以上で設定は終了です。

Agentforceアクションはどうやってサイトのログインユーザーを知るのか

さて、この設定を行うと、Agentforceアクションに、Experience Cloudサイトにログインしたユーザーが通知されます。通知は以下の2方面から行われ、指しているユーザーは同一です。

  1. UserInfo.getUserId()
  2. MessagingSession.MessagingEndUser.MessagingPlatformKey

1. UserInfo.getUserId()

先ほどの設定(拡張チャットメッセージング「ユーザー検証を追加」と組み込みメッセージングコンポーネント「ログイン情報ベースのユーザー検証の追加」)を行うと、Agentforceアクションの実行ユーザーがExperience Cloudサイトのログインユーザーに変更されます。(通常はAgentforceの既定のユーザー)

このことは、AgentforceのアクションにApexアクションを設定して、その内部でUserInfo.getUserId()を実行すると観察できます。

つまり、Agentforceアクションの実行は全て、Experience Cloudのログインユーザーの範囲に制限されるのです。これは以下のようなパーソナライズを適用できる、強力な機能です。

  • 実行ユーザーの情報の取得
  • オブジェクトアクセスや項目アクセスの制限
  • 実行可能なApexクラスなどの制限

そして、この実行ユーザーの設定をごまかすことは、できません。ユーザー情報は安全に連携されてくるのです。

(短くて恐縮ですが、本ブログの要点は以上です。ただし、ユーザー検証の仕組みについてより深く理解されたい方は、この先もお読みください。)

2. MessagingSession.MessagingEndUser.MessagingPlatformKey

こちらも探ってみましょう。

Apexアクションの入力項目に「Routable Id」変数を設定すると、SalesforceのId文字列が連携されてきます。

(実のところ入力項目名がmessagingSessionIdStringだと、変数設定しなくてもAtlas推論エンジンが推測して値が連携されてきますが、確実な動作のために変数設定します。)

このId文字列を足場にSOQLでクエリすると、以下のような情報が引き出せます。(抽出コードはこちら)

{
  "messagingSessionIdString": "0Mwgxxxxxxxxxxxxxx",
  "messagingSession": {
    "messagingEndUserId": "0PAgxxxxxxxxxxxxxx",
    "messagingEndUser": {
      "messagingPlatformKey": "v2/iamessage/AUTH/SFDC/uid:005gxxxxxxxxxxxxxx",
      "name": "X Sato"
    }
  },
  "userInfo": {
    "userId": "005gxxxxxxxxxxxxxx",
    "userName": "x.sato.xxxxxxxx@agentforce.com"
  }
}

messagingPlatformKeyの末尾のID文字列と、userIdは常に一致しています。本質的には、UserInfo.getUserId()によって得られるものと同じです。

全てのパーソナライズはユーザーIDから行うべき

このユーザーID(userId値)を足場にAgentforceのアクションの動作を調整することで、Experience Cloudのログインユーザーに合わせたパーソナライズが可能になります。これはプレチャット(英語名: pre-chat)と異なり、たとえWebデバッグツールでスクリプトを改変しても変更できない確実な足場です。

実はこれだけではない「ユーザー検証」機能

拡張メッセージングのユーザー検証機能には、すでに紹介した「ログイン情報ベース」の方法の他に、「トークンベース」の方法があります。

トークンベースのユーザー検証機能は昨年の弊社ブログ「Service Agent に認証済みユーザの情報を提供する」に書かれているMessaging for In-App and Web (MIAW、現在はEnhanced Chatに改名)のユーザ認証の仕組みそのもので、本質的には以下のようなものです。(用語については前回ブログ「AgentforceとExperience Cloud組み込みメッセージングコンポーネントの関係」を参照してください。)

  • Salesforce組織に公開鍵を設定する。これはJWKSと呼ばれる仕様で、IDプロバイダーが公開しているJWKSを活用する方法と、JWKを手作業で設定する方法がある。
  • Web画面(昨年の弊社ブログではMIAW REST APIを使う任意のクライアント。または組み込みサービスリリースのスニペットを展開したWebページ)で(サイト独自の)ユーザー認証を行った後にJWTを取得し、拡張チャットメッセージングを初期化する時に設定する。
  • Salesforceは設定済みJWKSでこのJWTを検証し、検証できた場合のみ拡張チャットメッセージングを有効にする。

IDプロバイダがJWKSを公開しているケースについて図にすると、以下のようになります。

Salesforce自身もIDプロバイダとして動作しますので、以下のようにSalesforce認証を行う外部Webサイトを作成して動作を確認してみましょう。

外部サイト側

  • 外部サイトは、ログイン認証をSalesforce環境に設定した外部クライアントアプリケーションで行う。この外部クライアントアプリケーションでは、Web画面の認証フローとJWTベースのアクセストークン発行を有効にする。(詳細についてはこちらをご覧ください。)
  • 外部サイトに組み込みサービスリリースのスニペットを貼り付ける。
  • 取得したアクセストークン(JWT)を組み込みサービスリリースに設定する。

Salesforce側(JWKSのみ掲載)

  • Setup: 機能設定 -> サービス -> 組み込みサービス -> 拡張チャットユーザー検証
  • 画面一番下のJSON Webキーセットで、以下の画面の通りにSalesforceのJWKSを設定

  • 拡張メッセージングチャネルのユーザー検証でこのJWKSを指定

サイト全体のソースコードこちらに掲載しましたので、適宜ご参照ください。(なお、環境固有の文字列については匿名化しています。)

「ログイン情報ベースのユーザー検証」の場合と同様にAgentforceのApexアクションを観察すると、以下のような出力になりました。

{
  "messagingSessionIdString": "0Mwgxxxxxxxxxxxxxx",
  "messagingSession": {
    "messagingEndUserId": "0PAgxxxxxxxxxxxxxx",
    "messagingEndUser": {
      "messagingPlatformKey": "v2/iamessage/AUTH/t219tecptl484/uid:uid:005gxxxxxxxxxxxxxx",
      "name": "Guest"
    },
  },
  "userInfo": {
    "userId": "005gxxxxxxxxxxxxxx",
    "userName": "t219tecptl479_01@....ext"
  }
}

messagingPlatformKeyに注目してください。「t219tecptl484」は、先ほど登録したJWKSの名称です。また、「uid:005gxxxxxxxxxxxxxx」は、ログイン認証されたユーザーの、Salesforce組織におけるユーザーIDです。こちらは昨年の弊社ブログで確かめられた通り、ユーザー検証に使われたJWTのsubクレームが「uid:」プレフィクスの後に設定されます。

アクセストークンのクレームを見てみると、以下のようになっており、このことが確認できます。

{
  ...
  "sub": "uid:005gxxxxxxxxxxxxxx",
  ...
}

また、アクセストークンのヘッダ部のkidクレームを、JWKSで設定したURLでダウンロードされるJWKSデータと比較してみると、列挙されたJWKの一つにこのkidクレームに一致するものが含まれており、署名検証が可能であることがわかります。

アクセストークンのヘッダ部

{
  ...
  "kid": "CORE_ATJWT.00Dg5000003Gi2J.1767952265729",
  ...
}

JWKSの対応キー

[
  ... (他のキー)
  {
    ... (キーのデータ)
    "kid": "CORE_ATJWT.00Dg5000003Gi2J.1767952265729"
    ...
  }
  ...
]

署名が効いていることを確認してみましょう。外部サイトでアクセストークンを組み込みサービスリリースに設定する際に、トークンの内容に"A"を付け足すなどして改変すると、スクリプトエラーとなり、チャット窓が開かなくなります。期待通りにJWTの検証が行われているようです。

await embeddedservice_bootstrap.userVerificationAPI.setIdentityToken({
  identityTokenType: "JWT",
  identityToken: accessToken + "A" // <= トークンを改ざんするとチャット窓が開かなくなる。
});

なお、userInfoに報告されたユーザー(Name=t219tecptl479_01@....ext)は、Agentforceに設定されたエージェントユーザーです。このため「トークンベースのユーザー検証」を利用する場合には、実行コンテキストはパーソナライズされていないことに留意する必要があります。

振り返って、どうか

実案件では、ログイン情報ベースのユーザー検証の追加が選ばれることがほとんどでしょう。設定も簡単で、安全で、効果は確実です。トークンベースのユーザー検証も柔軟性が高い仕組みですので、既存サイトにAgentforceを出張させ、パーソナライズの効いたチャットを実装する際に便利に使えそうです。

ユーザー検証、拡張チャットV2での早期の対応を期待したいと思います。

最後までお読みいただきありがとうございました。

謝辞

外部サイトに組み込みサービスリリースのスニペットを展開する際には、以下のサイトを参考にしました。

なお、「2.2 Trusted Domains for Inline Frames の設定」を行うには、(Experience Cloudサイトではなく)Salesforce組織のサイト機能を有効にする必要がありますので、注意してください。