ACES エンジニアブログ

ACESのエンジニアブログです。

AIのUXは『Guidelines for Human-AI-Interaction』に基づいて決めよう——ACES Meetの事例を添えて——

1. はじめに

こんにちは。株式会社ACESのAIエンジニアの阿久澤です。長らく運動とは無縁でしたが、最近は村上春樹さんのエッセイ『職業としての小説家』に啓発されて、一日一回のランニングを日課にしています(彼は毎日1時間程度走るそうです)。HPは消費しますが、最大HPは上がっている気がしますね。

さてこのブログでは、AIとUXの関係性について弊社で特に意識しているポイントと、弊社のSaaS『ACES Meet』の開発における実践内容について紹介していきます。AIとUXの関係性については、日本のAI企業/開発者の中で強く意識されていると認識しています。例えば、LayerX 福島さんのブログの以下の言葉

AIで体験を構築する部分も、AIの精度は100%にならないという前提で、いかにその間違いをUX的に吸収できるかを考える必要があります。

AI-UXとAX(AI Transformation)というLayerXの挑戦』より引用

は、AIを機能に落とし込んでいく際のポイントを端的に表していると考えます。

さて、実際に機能開発をする上で「AIの間違いをUX的に吸収する」とは、具体的にどういったことでしょうか?このようなAIとUXの関係性について考える時、弊社ではMicrosoft Researchが提唱した『Guidelines for Human-AI-Interaction』(以下、HAIガイドライン*1を参考にすることが多いです。このガイドラインは人とAIが協働するUX設計のベストプラクティスを体系的に整理したものであり、具体の機能開発において守るべき原則や考えるべき観点を教えてくれます。

HAIガイドラインはChatGPTの登場より前の2019年に発表されたものですが、そのエッセンスはまだ錆びておらず、むしろLLM時代にあってその重要性を増しているものと考えています。弊社のResearch FellowでありCHIの専門家であるriku_arakawaさん(@rikky0611)が社内に普及させ、AIを機能に落とし込む際のUX設計の指針として弊社で重宝されてきました。

2. 『Guidelines for Human-AI-Interaction』の紹介

Microsoft Research が 2019 年に提唱した『Guidelines for Human-AI-Interaction』は、人とAIが協働する際のユーザー体験設計に関する18の原則(デザインガイドライン)を、4つのフェーズに沿って体系的に整理したものです。このガイドラインに沿った機能を開発する / UXを提供することで、ユーザーがAIを信頼し、安心して機能を利用するようになると期待できます。

それでは、ひとまずガイドラインをざっと眺めてみましょう。

フェーズ No 原則内容(日本語意訳) 英語原文
Initially
(導入時)
G1 システムが何をできるかを明示する G1. Make clear what the system can do.Help the user understand what the AI system is capable of doing.
G2 システムがどの程度うまくできるかを明示する G2. Make clear how well the system can do what it can do.Help the user understand how often the AI system may make mistakes.
During Interaction
(利用中)
G3 文脈に応じてタイミングよくサービスを提供する G3. Time services based on context.Time when to act or interrupt based on the user’s current task and environment.
G4 ユーザーの状況に関連した情報を提示する G4. Show contextually relevant information.Display information relevant to the user’s current task and environment.
G5 社会的・文化的規範に沿った体験を提供する G5. Match relevant social norms.Ensure the experience is delivered in a way that users would expect, given their social and cultural context.
G6 言語や振る舞いに偏見を含ませない G6. Mitigate social biases.Ensure the AI system’s language and behaviors do not reinforce undesirable and unfair stereotypes and biases.
When Wrong
(失敗時)
G7 ユーザーがAIを呼び出せる手段を提供する G7. Support efficient invocation.Make it easy to invoke or request the AI system’s services when needed.
G8 不要になったAI機能を簡単に終了できるようにする G8. Support efficient dismissal.Make it easy to dismiss or ignore undesired AI system services.
G9 誤ったときにユーザーが修正・回復できるようにする G9. Support efficient correction.Make it easy to edit, refine, or recover when the AI system is wrong.
G10 ユーザーの意図が曖昧なときに範囲を限定して対応する G10. Scope services when in doubt.Engage in disambiguation or gracefully degrade the AI system’s services when uncertain about a user’s goals.
G11 AIがなぜその結果になったかを説明する G11. Make clear why the system did what it did.Enable the user to access an explanation of why the AI system behaved as it did.
Over Time
(継続利用)
G12 過去のインタラクションを記憶・参照できるようにする G12. Remember recent interactions.Maintain short-term memory and allow the user to make efficient references to that memory.
G13 ユーザーから学習し、体験をパーソナライズする G13. Learn from user behavior.Personalize the user’s experience by learning from their actions over time.
G14 更新・適応は混乱を最小限に抑える G14. Update and adapt cautiously.Limit disruptive changes when updating and adapting the AI system’s behaviors.
G15 細かいフィードバックを得られるようにする G15. Encourage granular feedback.Enable the user to provide feedback indicating their preferences during regular interaction with the AI system.
G16 ユーザー行動の結果とその影響を伝える G16. Convey the consequences of user actions.Immediately update or convey how user actions will impact future behaviors of the AI system.
G17 AIの監視や挙動をユーザーが制御できるようにする G17. Provide global controls.Allow the user to globally customize what the AI system monitors and how it behaves.
G18 システムの更新や変更を通知する G18. Notify users about changes.Inform the user when the AI system adds or updates its capabilities.

こちらを見て何か染み入るものはありましたでしょうか。「うんうん」となっている方、さすがです。実務でかなりAIを使っておられることでしょう。逆にイメージがつかなかった方、この次の章で弊社事例をケーススタディとしてご紹介するので、ぜひそちらもご覧になってください。

さて、私としては上記のガイドラインの特徴を「人間中心」の視点と考えています。人間中心とはつまり、AIを単なる自動化ツールとしてではなく、人間の意思決定や行動を補助するパートナーとして位置づけています。例えば、

  • 「誤りを避ける」よりも「誤りがあったときにどう対処するか」を重視しています。
  • ユーザーがAIを「盲目的に信じる」のではなく、「AIがどのように結論に至ったか理解したうえで判断する」できるように、説明性や透明性を重視しています。

なお、AIとUXに関わるガイドラインとしては、本記事でご紹介するマイクロソフト版のHAIガイドライン以外にもいくつか例があります(例えばGooglePAIR Guidebookなど)。そうしたガイドラインの中で、マイクロソフト版は特に人間のメンタルモデルに焦点を当てて「人がどう気持ちよくAIを使いこなしていくか」の設計を丁寧に掘り下げている印象です。また抽象と具体のバランスが整っており、原理原則から実務に落とし込むのに役立つと私的には考えています。

💡 ※参考: A Comparative Analysis of Industry Human-AI Interaction Guidelines 逆にGoogleガイドラインはもう少し包括的で、例えば「どの業務をAIで代替するべきか」という企画や、「モデル訓練方法」といった開発部分まで言及があります

3. 弊社での事例

ここからは弊社のプロダクトACES Meetを事例として、実際の機能開発においてHAIガイドラインをどう活用してきたかご紹介します。 なお本記事では弊社の宣伝も含めてACES Meetを事例としますが、HAIガイドラインの論文にも事例は載っている(Table.1)ので、ご興味のある方はそちらもご覧ください。

3.1 問題設定: 話者分割

『ACES Meet』は、会議を効率的に記録・要約するためのAI議事録ツールです。Zoom、Teams、Google Meetといった主要なビデオ会議ツールと連携できるほか、音声ファイルを直接アップロードして文字起こし・要約を生成することも可能です。

このサービスの大きな強みのひとつが「誰がどの発言をしたか」を識別する 話者分割機能です。一見単純な処理ですが、会議データの特性によって思いの外複雑な処理になります。

たとえばZoom経由で取得した音声データでは、参加者ごとに別々のマイク音声が取得できる場合があります。この場合はマイクごとの分割が明確なので、話者の区別は比較的簡単です(これをマイク間の話者分割と呼びます)。ところが、ひとつのマイクを複数人が共有している「会議室録音」の場合、ひとつの音声ファイルの中に複数人の声が混在していますまた、ユーザーが音声ファイルをアップロードするケースも、基本的には「ひとつのファイル内に複数人の話者がいる」という状況を想定しなければならず、マイク内の話者分割を行う必要があります。さらに難しいのは二拠点にそれぞれ2人がいる(≒合計で2×2=4人が参加)ようなハイブリッド会議で、この場合はマイク内・マイク間の話者分割を併用する必要があります。

「マイク間話者分割」は単純で、それぞれ個別の音声ファイルごとに書き起こしを生成すれば、自動的に話者と発言を紐づけることができます。一方「マイク内話者分割」では、ひとつの音声ファイルから複数の話者を自動的に切り分ける機械学習モデルが動作しています。音声の特徴量をもとに「この声とこの声は同じ人物か、それとも別人か」を推定します。これは機械学習モデルの推定に依存しているため、どうしても誤りが生じます。声質が似ている人を同じ人物と判断してしまったり、逆に同じ人の発話を複数人と誤認してしまったりすることがあります。

ユーザーにとっては「議事録上で発言者が誰なのか分かる」ことが非常に重要であるため、話者分割の精度は体験価値に直結します。ただし、マイク内話者分割は機械学習モデルの推定である以上、完全な精度は望めません。また、ユーザーはACES Meetの導入時点では基本的にマイク内・マイク間という概念には馴染みがありません。このような状況下で、ユーザーがAIの挙動を理解し、AIの誤りを受け入れて使いこなすようなUXを作ることがゴールとなります。

3.2 HAIガイドラインの実践

[G1. Make clear what the system can do. / G2. Make clear how well the system can do what it can do] マイク間・マイク内の概念を明確に

先に述べた通り、話者分割には「マイク間の話者分割」、「マイク内の話者分割」の2種類が存在します。ここで重要なのは、ユーザーに「どちらの分割なのか」を明示することです。以下に、実際のACES MeetのUIでどう表現されているかを掲載します

上記は、youtubeなどで良くある動画のシークバーを話者ごとに表したものです(色が付いている部分は発言時間帯です)。録画時の状況としてはハイブリッド会議になりまして、ある会議室に3人と、自宅から参加している人物が2人います。赤色で囲われた名前は「発言者の名前」、オレンジ色で囲われた部分は「誰のマイクで収音しているか」を表しています。

この表記が重要なのは「マイク間の話者分割」、「マイク内の話者分割」で精度が異なるためです。マイク間の分割であれば安心して信頼してよいが、マイク内の分割については誤りが含まれている可能性があります。ユーザーが事前に「ここは信頼して良い / ここは誤りが含まれるかもしれない」ことを知ることで、認知負荷が下がり誤りの修正を効率的にできるはずです。これらの違いを理解してもらうことは、Guideline G1, G2が示す、「システムが何を、どの程度うまくできるのかを明示する」という原則の実践です。

次の節では、ユーザーがどのように誤りを修正するか見ていきましょう。

[G9. Support efficient correction] 人間が効率的に修正する工夫

マイク内話者分割(≒AIによる話者分割)は便利ですが、当然ながら誤りが発生します。大切なのは「誤りが起きないようにする」ことに加えて、「誤りが起きても人間が簡単に修正できる」ようにすること —— Guideline G9で提唱されている Support efficient correction の考え方です。

2種類の誤り

話者分割の誤りには大きく分けて2種類あります。

  • 過小分割: 本当は複数人が話しているのに、同一人物と判定されてしまうケース。例えば会議室でAさんとBさんが会話していて、両者の声が似ているため、AIが「同じ人」と誤認する場合
  • 過剰分割: 本来はひとりの人間が話しているのに、複数の話者として切り分けられてしまうケース。例えばAさんの声を「Aさん」と「Cさん」に分けてしまう、といった誤り

どちらが直しやすいか?

UXの観点からすると、どちらの誤りがユーザーにとって修正しやすいかが重要です。私たちが検討した結果、過剰分割の方が修正コストが低いという結論に至りました。なぜなら「複数に分かれた話者をまとめる(統合する)」操作は、非常に少ないクリック数で実現できるからです。

3クリックで話者を統合する様子

一方で過小分割をユーザーが人手で修正するのは容易ではありません。例えば「Aさん」に分類された会議中の発言をすべて確認し、Bさんの発言を見つけるたびにに話者ラベルを振り直すといったような、大きな負担を強いてしまいます。

ACES Meetでの実装方針

この知見を踏まえて、ACES Meetではソフトウェア・アルゴリズムの両面から効率的な修正をサポートしています。ソフトウェア面としては、上記のように数クリックで話者を統合するような機能をリリースしました。一方でアルゴリズム面では、あえて「やや過剰分割気味」に機械学習モデルをチューニングしています。つまり、多少多めに話者を切り分けてユーザーに後から統合していただく手間を許容しつつ、過小分割による負を引き起こす確率を最大限に抑えているのです。

💡「やや過剰分割気味」に機械学習モデルをチューニングするとは、recallとprecisionのバランス調整のようなものです。

また基本的に統合対象の話者は同じマイクに所属しています(「マイクAの話者1とマイクBの話者2が実は同一人物でした」というシーンは想像しづらいですよね)。そのために、前節でご紹介したような「マイク間・マイク内の概念をわかりやすく伝える」UIがあることで、「どの話者を統合すれば自然か」が明確になり、ユーザーは迷わず修正作業に取り組むことができます。

3.3 HAIガイドラインとの対応づけ一覧

HAIガイドラインには全18項目があり、本記事でそのすべてを掘り下げることはしません。その代わりに、前節で紹介したもの、出来なかったものも含めて、弊社の話者分割に関連するHAIの実践内容を一覧化して簡単にご紹介します。

フェーズ No 原則内容(日本語意訳) 話者分割機能における実践
Initially
(導入時)
G1 システムが何をできるかを明示する マイク内・マイク間の区別
G2 システムがどの程度うまくできるかを明示する マイク内・マイク間の区別
During Interaction
(利用中)
G3 文脈に応じてタイミングよくサービスを提供する N/A
G4 ユーザーの状況に関連した情報を提示する 会議参加者の中から話者割り当てを行う
(自動・手動)
G5 社会的・文化的規範に沿った体験を提供する N/A
G6 言語や振る舞いに偏見を含ませない N/A
When Wrong
(失敗時)
G7 ユーザーがAIを呼び出せる手段を提供する マイク内話者分割のon / offを切り替えられる
(対面会議を利用しない人はoffにすることができる)
G8 不要になったAI機能を簡単に終了できるようにする ソフトウェア: 容易に話者の統合ができる
G9 誤ったときにユーザーが修正・回復できるようにする アルゴリズム: 過剰分割気味のチューニング
ソフトウェア: 容易に話者の統合ができる
G10 ユーザーの意図が曖昧なときに範囲を限定して対応する N/A
G11 AIがなぜその結果になったかを説明する 発言と動画を1クリックで移動が可能
->ファクトチェックが容易
Over Time
(継続利用)
G12 過去のインタラクションを記憶・参照できるようにする
G13 ユーザーから学習し、体験をパーソナライズする ユーザーの声の特徴を記録し、自動で話者名を割り当てる
G14 更新・適応は混乱を最小限に抑える
G15 細かいフィードバックを得られるようにする 修正が簡単・直感的に行える
(話者単位、発話単位)
G16 ユーザー行動の結果とその影響を伝える ユーザーの修正に基づいて声の特徴を記録
G17 AIの監視や挙動をユーザーが制御できるようにする
G18 システムの更新や変更を通知する CSからの案内やサイト内での通知

ちなみに、N/Aはnot applicable(話者分割というユースケースと関わりが薄いもの)で、空欄は「本当はxxxの工夫の余地があるけど出来てないなー」と思ったところです。話者分割という機能一つ取っても、アルゴリズム・ソフトウェアの横断で考えるべきポイントがいくつもありそうなことが伝わりますでしょうか。

4. チームでの協働

先にも述べた通り、話者分割機能の開発にあたってはソフトウェア・アルゴリズムの両面からの工夫が盛り込まれています。そのため、ACES Meetでの機能開発にあたってはプロダクトチームとAIチームの間で多くの協働が必要でした。

一つ大きな問いは、こうした開発テーマの立案をPdMとAIエンジニアのどちらが主導するべきかという点でした。プロダクト開発において開発テーマ選定を主導するのは一般的にPdMだと思います。一方AIの挙動についての深い理解がないと、こうした開発テーマの立案は難しそうに思います。例えば「AIの失敗パターンが過剰分割と過小分割の二通りある」という感覚はAIエンジニアにとって容易に理解できますが、プロダクト全方面を見ている多忙なPdMが無意識的にキャッチアップするのは難しそうです。

この溝を埋める上で重要だったのは、第一に、AIエンジニア側の責務を開発に限定せずに「AIがどう使われるか」の機能設計にまで巻き込む(あるいは染み出す)ことだと思います。またそのためには当然連携を増やしていかなければなりませんが、その辺りの話は前回ブログもご参照ください: AIエンジニアのR&Dが事業に届くまで

もう一つは、『Guidelines for Human-AI-Interaction』のように体系化されたベストプラクティスをもとに議論することだと思います。HAIガイドラインMicrosoft Researchの研究結果に支えられた説得力を持ち、ともすれば個人の感性の問題に矮小化される危険があるかもしれないUXについての議論と意思決定を、スムーズにしてくれるものだと思います。

5. むすびに

HAIガイドラインの実践にはPdM、UXデザイナー、AIエンジニア、その他すべてのメンバーが知見を持ち寄り、リスペクトを持って協働することが大事だと考えています。ACESでは「人とAIが協働するビジネスプロセスの実現」を掲げており、これを共に実現していく仲間を求めています。もしこの挑戦に共感していただける方がいれば、ぜひ私たちと一緒に取り組んでいきましょう!(ここで採用サイトのリンクを貼る

*1:Amershi, S., Weld, D., Vorvoreanu, M., Fourney, A., Nushi, B., Collisson, P., Suh, J., Iqbal, S., Bennett, P., Inkpen, K., Teevan, J., Kikin-Gil, R., & Horvitz, E. (2019). Guidelines for Human-AI Interaction. CHI 2019. ACM. https://www.microsoft.com/en-us/research/publication/guidelines-for-human-ai-interaction/

ChatGPTのMCP連携とNotionの構造化で取り組む高性能ナレッジ検索

1. はじめに

こんにちは!ACESでR&D部門統括をしている久保(@seishin55)です。

ACESでは、事業としてAIを活用したプロジェクト推進(DXパートナーサービス)やプロダクト開発(AIソフトウェア開発)を行う一方、社内業務にも積極的にAIを取り入れています。今回は、その中でも他社にも応用可能と思われる「ナレッジ検索」の取り組みについてご紹介します。

当社ではドキュメント管理にNotionを採用しており、ドキュメント文化が根付いた環境の中で、体系的かつ豊富な情報が蓄積されています。この資産を最大限活用しない手はありません。また、チャットツールとして全社員にOpenAIのChatGPTを配布しており、日常的に業務で活用しています。そのため、ChatGPTから直接Notionの情報にアクセスできれば、より効率的に知識を引き出せる理想的な環境となります。こうした背景から、「ChatGPT上でNotionのデータを参照しながらナレッジ検索を実現する」ことが、本プロジェクトの出発点となりました。

あわせて、活用の窓口を一元化することも重視しました。個別のツールごとに専用のAIを作ると便利さはあるものの、利用者からするとどのAIに聞けばよいか迷う場面が増え、結果的に活用が広がりにくくなる場合もあります。その点、ChatGPTのような汎用的な対話環境を業務の中心に据え、必要なデータやシステムを裏側で繋ぎ込むことで、利用体験の一貫性を保つことによって、より良い体験の実現が期待されます。こうした発想もプロジェクトを支える背景のひとつです。

さらに、取り組みにあたっての前提として、Notionのデータ構造の特異性を認識する必要があります。Notionは人が使うには使いやすいインターフェースである一方で、AIが活用するにあたっては工夫が必要であるという点です。NotionのデータはAIに不向きであるという意見がSNS上では散見されます。例えば、以下の記事で説明されています。

note.com

今回の取り組みにおいては、Notionのデータ構造に対して処理を施し、AIに対しても読みやすい形に変換を行い、活用できるようにしています。当社では、Notionデータに限らず、AIが活用しやすいデータ形式に変換して、データを整備することは多く、この点の強みもあります。この記事は、いわゆるRAG (Retrieval-Augmented Generation)の取り組みにあたりますが、実際の利用にあたって十分な精度で活用を行うための、1事例としてもご参考にして頂ければと思います。

本記事では、実際の挙動をお見せした後に、構築した技術の全体像とそのポイントについて解説していきます。

2. 実際の挙動

まずは、実際の挙動です。ChatGPTに当社の強みについて質問した回答が以下になります。画像中にハイライトしている「エキスパートAI」という単語は社内で定義している単語になりまして、それを踏まえて回答を行ってくれています。回答のNotionマークを押すと回答に利用したNotionページを参照できるので、本当に正しいかどうかを人手で確認することも可能です。

実行例: 本記事のシステムでの挙動

ここで参照しているNotion記事の中には以下のように質問文にある「エキスパートAI」について記述してあるスライド画像が格納されており、今回はこれを参照して回答を作成してくれていました。

参照元のデータ

今回のシステム内では、画像データであってもデータ登録時に検索できるように処理(構造化)を行っており、検索することが可能になっています。この構造化処理を行わない場合、以下のような回答になるのですが、この場合、検索情報に必要な情報が不足していることに起因して、やや期待とズレた(断片的な)回答になってしまっていました。

実行例: 一般的なRAGの挙動

今回紹介するシステムでは、構造化処理によって回答の質も担保しながらChatGPTを活用し、利用しやすいインターフェースを構築することを行っています。

3. システムの全体像

今回ご紹介する機能の全体像を以下に示します。

システムの全体像

今回は、ChatGPTをインターフェースとして活用しつつ、裏側でコネクター(次章で説明します)に必要な機能(MCPサーバー)を実装しています。ChatGPTの内部のAIモデルがそのコネクターを活用した回答を生成します。技術スタックとしては、Microsoft Azureを中心に構成しており、データの管理にはSnowflakeやAI Searchを利用しています。ChatGPTを活用することで、裏側の仕組みだけ考えればよく、比較的簡易に構築が可能です。次章では、この構成を実現するためのポイントについて説明していきます。

なお、今回ご紹介する機能には執筆時点で、プレビュー版(Azure FunctionsのMCP bindings)やβ版(ChatGPTのカスタムコネクター)など本番利用に推奨されない機能が含まれます。実際に対応が追いついていない箇所もいくつか見られたので、期待通りの挙動にならない部分も一定存在します。ご自身の環境で利用する場合には、これらを踏まえて検討を行って下さい。(注目される領域ではあるので、早期に対応されることを期待はしています。)

4. 構築ポイント

4.1. ChatGPTとコネクター

まず、今回のシステム構成で重要なポイントであるChatGPTの「コネクター」機能を説明します。この機能は、ChatGPTが外部のデータソースを活用してチャットができるようになる機能になります。例えば、デフォルトで、Google DriveGmailと連携する選択肢があります。これらを選択することで、チャットを行う時に、適宜AIが判断して情報参照してくれるようになります。

以下の記事がコネクター機能についての公式記事になります。プランによって使える範囲が異なるので、使いたい場合は確認が必要です。また、コネクター機能は執筆時点で発展途上で更新も早いため、新規のコネクターなど随時追加されています。時折確認してみると機能アップデートされているかもしれません。

help.openai.com

ここまでは、ChatGPT内で事前に用意されたコネクターの話でしたが、このコネクター機能の連携先は自前で用意することも可能です。今回はこの機能を利用しました。このように、自前で用意したデータに対してアクセスできるようにするオプション機能を「カスタムコネクター」といいます。この機能の仕様には注意すべき点があるので、これは次節に説明します。

なお、実はデフォルトのコネクターとしてNotionも対応されていまして、こちらを活用することで、基本的なNotionの参照は実現できます。便利な機能なのでお手軽にまずは利用されることをおすすめします。一方で、データの検索性能はサービス(Notion⇔ChatGPT)側に依存するところではありますので、内部的な検索性能を更新することはできません。後述する構造化の処理を挟み、性能の改善を行いたかったため、今回はカスタムのコネクターとして独自にデータソースを用意することとしました。例えば、2章でお示しした実際の動作で行ったような画像データに対する検索性能など検索できる性能が拡張されています。*1

4.2. カスタムコネクターMCP

カスタムコネクターを使えば、独自に用意したデータを活用できることは前節で触れました。ここでは、カスタムコネクターについて深堀ります。ChatGPTをカスタムコネクターに接続するためには、「MCPサーバー」を立てる必要があります。AIの界隈では「MCP」は一般的な単語になりつつありますが、MCPとは、Model Context Protocolの略であり、AIエージェントにツールを持たせるための標準規格になります。この規格に則って開発を行うと、同じ規格に対応したクライアント(ここではChatGPT)に簡単に接続できます。ChatGPTのカスタムコネクターはこの規格に対応しており、MCPサーバーを用意することで接続することが可能です。(MCPについてもっと知りたい方は検索してみると丁寧に解説してある記事も出てくるかと思います。)

そのため、カスタムコネクターを利用するためには、MCPサーバーを立てる必要があります。MCPサーバー自体は任意にAIエージェントが利用するツールを作成することができるのですが、カスタムコネクター機能は情報検索の利用に制約が掛かっておりまして、使えるツールに制約があります。具体的には、 searchfetch のツールのみが利用可能で、それぞれ、テキストから検索、と、ドキュメントIDから詳細情報の取得、の機能になります。仕様に則って、この2つのツールのMCPサーバーを用意することによって、ChatGPTに接続することが可能です。カスタムコネクターの詳細については以下の記事にありますので実際に取り組む際はご参照下さい。

platform.openai.com

なお、このカスタムコネクターはβ版であることには注意が必要です。例えば、本来であれば、作成したカスタムコネクターをチーム全体に展開したいのですが、β版のため制限が掛かっています。今後開発が進み、正式リリースされることが待たれます。

4.3. MCPサーバーの構築

では、MCPサーバーを構築することを考えます。MCPサーバーの構築方法自体は様々あるので、手段はどのようでも構いません。ここでは、MCPサーバーを簡易に構築することが可能なAzure FunctionsのMCP機能で開発を行いました。これを活用すると、基本的に必要となるツールの関数を記述するだけでMCPサーバーを作成することができます。以下にドキュメントがあるのでこちらを参照できます。

learn.microsoft.com

本記事では、ChatGPTに接続しますが、MCPは標準規格のため、例えば、ClaudeやCursorなどMCPに対応しているサービスでも利用することも可能です。また、執筆時点においては、本機能はプレビュー版になりますが、先日のAzure OpenAI Service Dev Dayでロードマップも公開されており、Streamable HTTPとよばれる通信規格への対応なども含めて着実に対応される模様です。

ChatGPTのカスタムコネクターの接続はOAuth認証にも対応がされています。今回はMCPサーバーにOAuthの実装を施すことも考えました。MCPサーバーの認証として、API Managementを使う構成を公式で公開されていたので、これを活用しました。つまり、API ManagementをMCPサーバーとChatGPTの間に挟むことで認証の機能を搭載しました。詳細については以下のドキュメントが参考になります。

learn.microsoft.com

4.4. Notionとデータ管理

前節までで、ChatGPTと独自データの連携の方法は説明しました。最後に、独自データ側の整備についても説明したいと思います。システム全体像でお示ししたように、対象となるデータソース(ここではNotion)をSnowflakeを介してAzure AI Searchに保存することで、検索対象のデータとして登録することができます。自動で定期的に同期を行いつつ、データを最新に保つことで、AIエージェント側はAzure AI Searchの中のデータを参照するだけになります。

さて、この登録するデータですが、Notionデータを検索しやすい形に独自の変換(構造化)を施しています。まず、NotionのAPI経由で取得できるデータは個別の記事の全文が取れるというわけではなく、ブロックとよばれる記事ページ単位より細かい単位で取得されます。そのため、データの取得後にページ全体をAIが理解しやすいMarkdown形式でまとめ直しています。また、それに対して構造化処理をさらに行っており、例えば、画像データを説明する文章に変換するなど、AI、人にとっても分かりやすい形式に変換しています。これらを最終的には検索しやすい形式、つまりチャンク化(文章を適切に分割)等を行った上で、Azure AI Searchに格納しています。

冒頭でお見せした実際の挙動の中で参照したスライド画像は以下のような形に変換を行って、データの保存を行っています。

# ACES のエキスパート AI

ChatGPT などの汎用LLM(=優秀な新卒)では対応が難しい、業界・業務の専門知識や企業独自のナレッジを融合し、個社の強みと企業特性を踏襲した「エキスパート AI」を開発しご提供します。

## 汎用的な生成 AI
- 例: OpenAI など
- 「優秀な新卒AI」が業務を部分的に効率化
- 教科書に記述されている知識
- インターネットに公開されている情報
- 一般論な考え方

### 対応可能な業務
- 一般に公開されている情報を調べる業務
- 与えられた情報単体を整理する業務
- 一般論や型に沿ってアイデアを列挙する業務

## エキスパート AI /ACES
- 個社の強みと企業特性を踏襲した AI 開発
- お客様の生の声、リアルな情報
- 企業独自の業務の進め方やノウハウ
- 自社内に蓄積する情報やナレッジ

### 対応可能な業務
- 業界特有のルールや暗黙知を踏まえた業務
- 自社に蓄積されたナレッジを理解した業務
- 属人的なノウハウを必要とする高度な業務

画像の場合、単に文章化するだけではなく、全体的な位置関係も踏まえて構造的な文章にする必要があるため、一定の工夫が必要な場合があります。今回はこのような構造化処理を行うことによって、回答精度を向上させています。

5. さいごに

本記事では、ACESにおけるAI活用事例の一つとして、Notion × ChatGPTによる社内ナレッジ検索の取り組みをご紹介しました。この仕組みが情報資産を最大限に活かし、業務効率を高める上での参考になれば幸いです。今後も、社内外に役立つ取り組みやノウハウを積極的に発信していきたいと考えています。

関連する取り組みの紹介ですが、今回ご紹介したChatGPTでの利用の他に、同様のデータを参照するボットも社内Slack上でも稼働しています。AIエージェントと人が協働する場をつくるために、どのようなインターフェースや仕組みが有効かを試行しながら、最適な形を探っています。また、近年注目される「コンテキストエンジニアリング」の概念とも関連し、RAGやメモリ管理といった技術の活用も進めていきます。

AIの領域は、LLM(大規模言語モデル)の進化を背景にかつてないスピードで変化しています。大規模モデルの性能向上だけでなく、それを活用するためのインフラやツールも日々進化を続けています。ACESでは、この変化をいち早く捉え、スピード感を持って試行・導入を重ねることで、より大きな価値提供につなげていきたいと考えています。

ACESでは、AI活用を共に推進するパートナーとしてご支援しています。RAGの精度改善をはじめとする各種ソリューションや、業務改善や事業開発など、ニーズに合わせたサポートをご提供しています。ぜひ下記ページよりお気軽にご相談ください。

dxpartner.acesinc.co.jp

また、ACESでは共にAI活用を進めていく仲間も募集しています。ご興味をお持ちの方は、ぜひお問い合わせください。

recruit.acesinc.co.jp

*1:カスタムのコネクターを利用したかった背景としては、単に今回の取り組みで利用したいというだけではなく、デフォルトで対応されていないデータソースを含めてどの程度展開可能性があるかの検証の目的もあります。今回はNotionデータを対象としましたが、同じスキームで任意のデータに展開することができます。本文中にも記載をしましたが、デフォルトのNotionのコネクターでも一定対応できる範囲なので、まずはそちらの利用からご検討をおすすめします。

AIエンジニアのR&Dが事業に届くまで

  • 1. はじめに
  • 2. ACESのR&D部門とAIエンジニア
    • 2.1 組織図上の立ち位置
    • 2.2 何を作っているか
  • 3. 顧客に価値を届けるまでの3つの壁
  • 4. 【作る】R&Dとソフトウェアの接続
  • 5. 【価値を届ける】事業部との連携
    • 5.1 要求の受入口を絞る
    • 5.2 事業部の中に入る
    • 5.3 優先順位を付ける
  • 6. 【改善・拡張】アーキテクチャ戦略
  • 7. 今後の課題 - 大LLM時代への適応
  • 8. むすびに

1. はじめに

初めまして、株式会社ACESのR&D部門でAIエンジニアをしている阿久澤(@kei_akuzawa)というものです。

採用面談の場ではACESでAIエンジニアとして働くことの魅力や特徴についてよく聞かれます。 私が強調するのは「社会実装と付加価値の実現にこだわっている」というポイントです。このポジショニングは、特にインターンとして応募して下さる大学生/大学院生の方に刺さっているような実感があります(当たり前ですがインターンを検討している方の多くは、自身の培ってきた技術がどのように社会に役立つかを試す場を探しているのだと思います。)

とはいえR&Dと事業の接続は一般論としても非常に難しいものだと思います。上記のように、我々はR&D活動と事業の接続に対して一定の自信を持っているものの、さまざまな問題が噴出しているのも事実であり、継続的な改善・課題解決に取り組み続けています。

本ブログでは、R&Dと事業の接続に向けてAIエンジニアチームが意識していることや、課題解決に向けた格闘の歴史について簡単にご紹介します。会社ごとの事情によってポイントは変わるかと思いますが、ACESにおけるN=1のケーススタディに興味を持っていただければ幸いです。

💡なお、本記事で紹介する取り組みは松田達哉さん、久保静真さん、田村浩一郎さんを中心とするチーム全体の成果です。一方で、記事の内容に誤りや不十分な点がありましたら、その責任は筆者(阿久澤)にあります。また記載内容は個人の視点・解釈が多分に含まれており、ACESとしての公式な見解を示すものではないことをご承知おきください。

続きを読む

AI研究開発の成果はどう評価する?悩みに悩んだKPI設計を全部話します

みなさま、こんにちは。安藤(@anpyan)と申します。株式会社ACESでプロダクトマネージャーをしています。

私の所属するR&D部門では、東大松尾研究室出身メンバー達を中心とした専門家集団が最先端のAI技術研究を行っています。私たちの成果は、DXパートナーサービスの事業部や、ACES MeetをはじめとするAIソフトウェアサービスの事業部など、複数の事業部にAIモジュールとして提供され、実際のプロダクトやプロジェクトで活用されます。ざっくりと図にすると下記のような流れになります。

今回は、そんなR&D部門のKPIについてのお話です
この記事では以下を説明します。
・R&D部門特有のKPIの難しさ
・KPIの具体的な設計(アウトプット量・質・アウトカム)
・KPI導入後に得られた効果と残課題

KPIとは

KPI(Key Performance Indicator)とは、目標の達成度を測るための指標です。つまり「どれだけうまくいっているか」を客観的/定量的に評価するためのものと言えます。プロダクトマネジメントにおいてKPIの設定と運用は非常に重要です。

R&D部門におけるKPIの難しさ

一般的なプロダクトの場合、例えばユーザー数やMRR(月間の収益)やチャーンレート(解約率)などがKPIとしてよく使われます。多くのユーザーに利用されれば成功、そうでなければ失敗とシンプルで分かりやすいです。また特定のプロジェクトの場合は業務改善効果やコスト削減効果などを計測することもできます。

しかし、R&D部門が作るAIモジュールにおいては、成果がすぐに数値として現れにくかったり、直接的に売上やユーザー数や業務改善効果に結びつかないケースも多く、KPIの設計は本質的に難しい課題です。

KPIを通じて知りたいことを整理する

私たちACESのミッションは「アルゴリズムで、人の働き方に余白をつくる。」です。このミッションのもと、R&D部門では最先端のアルゴリズムを独自モジュールとして開発し、技術的な探求と実際のビジネス価値創出の両立を目指しています。

私たちが取り組むべき技術課題はまだまだたくさんありますが、一方で、単に技術の数や量を追求しすぎるとリリース自体が目的になってしまい、顧客課題やビジネス価値が置き去りになってしまう、いわゆる「ビルドトラップ(作ることが目的になってしまう罠)」に陥ってしまうことがあります。

そうならないためにも、アウトプットの量だけでなく、アウトプットの質や、アウトカム(効果や結果)も併せて計測する必要があります。

ここまでの話を踏まえると、我々R&D部門のKPIには以下の要件が求められます。

  • R&D部門の努力や取り組みが直接的に影響できる指標であること
  • アウトプットの「量」を計測できること
  • アウトプットの「質」を計測できること
  • アウトカム(効果)を計測できること

さらに、管理すること自体が目的にならないよう、以下の要件も必須です。

  • できるだけ簡単に計測可能であること

これらを満たすKPI設計と運用が、私たちのような最先端技術の研究開発とビジネス価値創出の両立を目指すチームにとって、大切な鍵となります。

KPI1: アウトプットの量

まずはアウトプットの量、すなわち開発生産性についてです。

私たちのR&D部門では、新技術の調査や実験を繰り返すことも重要ですが、生み出した技術を事業部やお客さまに届けることも重視しています。新技術やプロトタイプをいかに速くフィードバックループに乗せられるかが研究開発の生産性に大きく影響するため、アウトプットの量を測る指標として、Googleが提唱したDevOps指標「Four Keys」の一つであるデプロイ頻度に着目しました。

具体的には「d/d/d (deploys/day/developer):開発者1人1日あたりどれだけ頻繁にデプロイ(リリース)しているか」を計測しています。

これにより、チームがスピーディかつ継続的にビジネス価値を届けられているかを確認できます。

KPI2: アウトプットの質

次にアウトプットの質です。

R&D部門が生み出すアルゴリズムやAIモジュールに求められる質とは「正確さ」や「汎用性」の高さだけではありません。私たちが特に重要視しているのは、顧客が直面する具体的な課題や業務に特化して価値を提供できる「エキスパートAI」であることです。

エキスパートAIとは、一般的な汎用AIをベースに、特定の業務領域の専門知識や課題解決力を強化したAIモジュールを指します。エキスパートAIは汎用的なAIでは対応しきれない、より実践的な課題解決力を持ちます。

質の評価には他にも「処理速度」「スケーラビリティ」「メンテナンス性」などなど多くの要素が考えられますが、これらを個別に計測すると複雑化しやすいため、私たちは汎用AIがエキスパートAIへと専門特化していく手法やプロセスを Expertization(エキスパタイゼーション) と呼び、その成熟度をシンプルかつ実務的に評価する指標として、以下のような5段階の Expertizationレベル を設定しています。

Expertization
レベル
内容
レベル1 汎用的な基盤技術をベースとしたAIモジュールです。特定領域への専門特化はこれから進めていく段階です
レベル2 特定の業界や業務に関する専門知識を組み込み、専門性を持ったAIへの第一歩を踏み出したAIモジュールです。汎用AIでは難しい領域特化型の処理が可能になります。
レベル3 専門性をさらに高めるための独自機構や改善プロセスを内蔵したAIモジュールです。単なる専門知識の導入を超え、継続的に特定分野への適応度を高めるための仕組みが組み込まれています。
レベル4 特定業界や業務の具体的課題に対し徹底的に最適化されたAIモジュールです。顧客の業務プロセスや固有の要件を深く理解し、高い適応力を持ちます。
レベル5 業界トップレベルの性能を持ち、顧客にとって「なくてはならない」存在となったAIモジュールです。競合製品や他の手段と比較して強力な優位性を持ち、顧客の意思決定において第一選択となります。

これによって、多数あるAIモジュールの価値、特に「エキスパートAIを軸にどのような成熟度にあるのか」が可視化されました。

KPI3: アウトカム

最後にアウトカムです。

私たちのR&D部門の最終的な目的は、単にAIモジュールを開発するだけではなく、社内で認知され、販売され、事業部を通じてお客さまに届けられ、最終的にはお客さまの環境で稼働し価値を生み出すことです。

そのため、アウトカムの計測では次のような観点を設定しています。

  • AIモジュールが販売されているか
    • AIモジュールが社内で認知され、事業部のプロダクトやプロジェクトで採用・販売されている数を計測します。
  • AIモジュールが開発活用されているか
    • AIモジュールが事業部のプロダクトやプロジェクトにおいて開発活用されている数を計測します。
  • AIモジュールが稼働しているか
    • お客さまの業務環境において実際に稼働しているAIモジュールの数を計測します。

これらはそれぞれ、DXパートナーサービスでの 販売 → 開発活用 → 稼働という順番で進むプロセスに対応しているため、前段階の指標が次の段階の先行指標として機能します。例えば、販売数が多いソフトウェアは、その後の開発活用数や稼働数が伸びることを予測できます。また、販売数に対して開発活用数や稼働数が伸びていない場合は、導入や活用に何らかの課題があることを早期に把握できます。

また、アウトカムの観点を持つことで「なぜ作るのか」を考える必要が出てきます。技術的に優れたエキスパートAIであっても、実際に顧客価値として届けられなければ本来の目的を果たせません。どんな顧客のどんな課題を解決しようとしているのか?その顧客は今その課題をどうしているのか?どうやって顧客に届けるのか?などを考えることでビジネス価値をより意識した開発を行うことが可能になります。

KPIを設計/計測して分かったこと

これまで「アウトプットの量」(KPI1)の計測は行っていたのですが、ここに「アウトプットの質」(KPI2)と「アウトカム」(KPI3)を追加したことで、以前は曖昧だったAIモジュールの成熟度や活用状況が明確になり、チームとしての意思決定がスムーズになりました。

具体的には、次のような判断や議論が可能になっています。

  • 「このAIモジュールはまだ完成したばかりで成熟度は高くない(レベル2)けど、想定以上に販売が伸びている。もっと積極的にリソースを投入し、成熟度を高めることでさらに大きな価値を提供しよう」
  • 「こちらのAIモジュールは成熟度が高く(レベル4)、多くのお客さま環境で実際に稼働している。しかし最近新規の販売が伸び悩んでいる。何らかの課題が潜んでいるはずなので、詳細な分析をして次のアクションにつなげよう」

このように、KPIを通じてAIモジュールごとの状況を定量的に把握できるようになった結果、チーム全体の判断や議論の質が向上しました。

まだまだKPIには課題も多い

KPI1に加えてKPI2と3の計測を始めたことで数多くのメリットが得られましたが、一方で解決すべき課題や改善ポイントも浮かび上がっています。課題はたくさんありますが、ここでは以下の2点を挙げます

① 「アウトプットの質」のレベル評価基準をもっと明確化したい

「Expertizationレベル」という指標は、汎用AIがエキスパートAIへと専門特化していくプロセスをシンプルに評価できるよう表現されています。しかし、実際に運用してみると、ソフトウェア品質に関連する複数の要素が絡み合い、レベルの判定が曖昧になりやすいことがわかりました。現在は、これらの要素や関連する技術・手法の整理・構造化を進めており、今後はそれらを踏まえ、より客観的かつ実務的に運用できるよう評価基準を整備していく必要があります。

② 「アウトカム」の精度を改善したい

現在、AIモジュールの「販売状況」として、どれだけのサービスやソリューションで “採用されているか” の数で計測していますが、採用されている中でも ”よく提案されているもの" と "あまり提案されていないもの” に分かれそうです。できれば「事業部からお客さまに対してされている提案回数」や「提案された顧客の反応」のような高解像度な把握もしたいです。

とはいえ、逐一提案数や反応を記録するのは負担が大きいため、私たちが提供しているACES Meet(会議や商談の音声を音声認識し議事録を作成できるAIサービス)を活用して、商談中にどのAIモジュールが提案されたか・顧客の反応はどうだったのかを自動計測するなどの方法を考えています。

さいごに

本記事では、ACESのR&D部門におけるKPIの設計と運用についてご紹介しました。 私たちは最先端のAI技術を単なる研究成果にとどめるのではなく、実際のプロダクトやサービスとしてお客さまに届けることに情熱を注いでいます。

もし本記事を通じて、ACESに少しでもご興味をお持ちいただけましたら、ぜひお気軽にカジュアル面談でお話ししましょう!

CREの業務改善:トライアル分析をDifyで効率化した話

あいさつ

はじめまして、ACESでCREをしている村上です。

最近暑くなってきましたね。暑くなるとだんだん温かい食べ物を食べられなくなるはずなのですが、今年はまだこれという冷たい食事に巡り会えておらず気がついたら行きつけのラーメン屋に行っています...

こんなことをしてるから痩せないんですね。夏の暑さに負けないようにしつつ気を引き締めていこうと思います。

今回は、以前話したトライアルの結果を分析する取り組み (リンクはこちら) について、その取り組みが今ではどうなっているのかについて紹介します。

トライアルの内容把握の課題

以前の記事で、トライアルの内容をひたすら見ることでトライアルの勝ちパターンと負けパターンを分析したという話をしました。

以降もトライアルの傾向を確認するようにしているのですが、トライアル件数が増えてきたこともあり、少しずつ負担が増えていました。

そこで、報告の内容を一括で取得しAIで分析することで、効率よく内容把握できるようにならないかと考え、Difyを使った効率化に取り組み始めました。

補足: Difyとは

AIアプリケーションをノーコードで開発できるプラットフォームです。画面上で要素を繋ぎ合わせるだけで簡単にAIエージェントを作成することができます。

LLMを使った内容把握の効率化

ACESではトライアルの内容をSlack上で報告する運用になっていたので、まずはSlackから情報を抜き出して出力する方針でDifyでワークフローを作成しました。

補足: ACESのDify環境

ACESでは機密情報を含むデータを安全に使えるようにACES AgentHubという独自の環境を作成しています。

この環境の中でDifyのOSS版をセルフホストしているため機密情報であっても問題なくLLMの入力として利用することができます。

ACESではDifyの活用を推進しており、非エンジニアの方でも利用できるように定期的に勉強会が開かれています。

作成したワークフローの内容

  • Slackからの情報取得
    • 企業名を入れると、その企業名を含むSlackの投稿を取得するAPIを実行
    • APIの出力を整形してLLMの入力にする
  • LLMによる情報抽出
    • Slackで取得した内容には関係のない情報も含まれているのでLLMで必要な投稿のみを抽出
    • 抽出した内容をフォーマットに沿って要約
      • その際に以前トライアルを見るときに重点的に見ていた点をフォーマットに反映しました
        • 顧客が何に困っていて、どのような期待を持ってトライアルを始めたのか
        • 実際にプロダクトを使う中で詰まった部分や質問されたこと
        • 最終的に顧客の目的は達成できたか、その理由は何か

LLMによるトライアル全体の分析

Difyによって個々のトライアルの情報を簡単に確認できるようになったため、追加でトライアル全体の内容をまとめて成約理由・失注理由にはどのようなものが多いのかどういった改善点があるのかの分析を行なっています。

  • Notionへの情報整理
    • Difyの出力内容をNotionに記載
    • Notionの記事をPDF化
      • Notion記事のフォーマットが特殊なので読み込める形に変換する意図で行っています
        • (obsidianに変えるなど上手い方法もありそうですが、一旦この形にしています)
  • LLMによる分析
    • PDFをLLMに入れて内容を分析

結果と今後の展望

結果

トライアル中のMTGは複数回行われておりこれまでそれぞれのMTGの内容を確認していたのですが、Difyを使うことにより複数MTGの内容を確認しなくてもトライアル全体の内容を把握することができるようになりました

また、全体の分析も (たまに間違うこともありますが) 素早くできるようになりました。

結果として全体で1時間程度短縮できるようになったのではと思っています。

今後やりたいこと

利用状況データの統合

現状トライアルの分析はユーザーの声をもとにした定性的な内容になっていますが、実際の分析ではどの機能をどれぐらい使っていたのかという定量的な内容も重要になってきます。

そのため実際の利用状況をDBから取得して、それもLLMに入れられるようワークフローを強化していくことが今後必要になってくると考えています。(現状はこの部分は人力で行っています)

複数企業の分析

個々のテナントのトライアル情報も重要なため現状は企業ごとにDifyで出力し、その結果をまとめてLLMに入れるという工程をとっていますが、現在手動で記載している部分もどんどん自動化していくことでより簡単に分析を行えるようになるのではと思っています。

最後に

今回は、Difyを活用してトライアルの内容把握を効率化した事例について紹介しました。

今後も引き続き、顧客の現状に向き合い、どうすれば顧客により満足してもらえるかを考えていきたいと思います。

もしこの記事を読んで「CREに興味が湧いた」という方や、「ACESでどんな働き方ができるのか知りたい」という方がいましたら、ぜひお気軽にご連絡ください!

ACESの採用情報はこちら↓

youtrust.jp

youtrust.jp

Auth0徹底活用ガイド:導入エンジニアが知るべき技術的ポイントとベストプラクティス

タイトル

こんにちは、株式会社ACESの共同創業者/ソフトウェアエンジニアの三田村です。

Auth0を社内に導入し、その過程で学びと課題に直面しました。本記事は、これからAuth0の導入を検討している、あるいは導入初期段階にあるエンジニアの方々に向けて、Auth0を効果的に活用するための技術的なポイントやベストプラクティスを共有することを目的としています。

本記事は、執筆の効率化のために生成AIの助けを借りて作成した部分を含みます。ただし、記事内で解説している技術的な内容やコード例は、すべて筆者の実体験に基づき検証・修正しており、情報の正確性を担保するように努めています。

また本記事はとても長いので、全てを詳細に読まずに適宜飛ばし読みしていただき、必要な部分を脳内のインデックスに留めておいていただければ幸いです。

はじめに:Auth0導入の動機と本記事で得られること

現代のアプリケーション開発において、堅牢かつ柔軟な認証・認可基盤の構築はとても重要です。我々のチームがAuth0を選択した背景には、開発者フレンドリーな設計思想、豊富なカスタマイズオプション、そしてスケーラビリティへの期待がありました。特に、カスタムアプリケーションへの組み込みやすさや、多様な認証方法への対応力は大きな魅力でした。

弊社では、複数のサービスにまたがる共通認証基盤を構築するという目的があり、その実現のために設計や実装において汎用性を重視しました。

しかし、Auth0はその多機能性ゆえに、導入初期には学習コストが伴うことも事実です。テナントの概念、認証フローの選定、セキュアなトークン管理、ログイン体験のカスタマイズ、そして既存システムや外部サービスとの連携など、エンジニアが直面する課題は少なくありません。筆者自身も、これらの点で試行錯誤を繰り返しました。

本記事を執筆したモチベーションは、自身が導入プロジェクトを進める中で、特定の機能に関する部分的な記事は多く見つかるものの、プロジェクト全体を網羅した包括的な導入事例が少ないと感じたことにあります。公式ドキュメントでは各要素の説明が詳細に書かれていますが、それらを実践的な視点で繋ぎ合わせ、一つの流れとしてまとめた記事があれば、これから導入する方々の助けになると考えました。

本記事では、Auth0のコアコンセプトを解説し、次に開発・ステージング・本番環境の構築といったセットアップ手順へと進みます。さらに、認証フローの実装方法、Auth0 Actionsを用いた認証フローの拡張、ユーザー管理とID連携の具体例、セキュリティ強化策、そして開発・運用時のヒントといった、技術的な内容を提供します。

本記事を通じて、読者の皆様がAuth0導入プロジェクトを進め、そのポテンシャルを引き出すための一助となることを目指します。Auth0のようなIDaaS(Identity as a Service)ソリューションは、Amazon CognitoやKeycloakといった他の選択肢と比較されることも多く、本記事がAuth0の特性を理解する上での参考情報となれば幸いです。

また、今回弊社ではAuth0をEnterprise Planで契約しました。プランによっては利用できない、または利用できる数に制限がある機能があるため、詳しくは公式サイトを確認してください。

Auth0のコアコンセプトを理解する

Auth0を利用するためには、まずその基本的な構成要素と、それらがどのように連携して機能するのかを理解することが必要です。これらのコアコンセプトは、Auth0における認証・認可システムの設計と実装の土台となります。

テナント (Tenant): 分離と管理の基本単位

Auth0におけるテナントは、すべての設定とアセット(アプリケーション、コネクション、ユーザープロファイルなど)を定義、管理、保存するハブです。テナントを作成すると、your-tenant-name.auth0.comのような一意のAuth0ドメインが割り当てられ、このドメインがAuth0 APIへのアクセスやユーザー認証時のベースURLとなります。

テナント名は一意である必要があり、小文字の英数字とハイフンのみ使用可能、作成後は変更や削除後の再利用ができないといった制約があります。また、テナントは特定のリージョンに紐づきます。論理的な分離を提供するため、開発、ステージング、本番といった異なる環境ごとにテナントを作成することが推奨されています。

本番環境では、シームレスでセキュアなユーザー体験を提供するために、カスタムドメインの利用が推奨されます。テナント設定はAuth0ダッシュボードから行い、環境タグ(Production、Staging、Development)を指定することで、例えば本番テナントはより高いレート制限が付与されるなどの利点があります。

アプリケーション (Application): 認証・認可の対象

Auth0におけるアプリケーションとは、Auth0を認証や認可のために利用するソフトウェアを指します。これは特定の実装形態(ネイティブアプリ、シングルページアプリケーション(SPA)、従来のウェブアプリケーションなど)を問いません。

主なアプリケーションタイプには以下のものがあります。

  • Regular Web Application (RWA): サーバーサイドでロジックの大部分を実行するウェブアプリ(例: Express.js, ASP.NET)。
  • Single Page Application (SPA): ブラウザでUIロジックの大部分を実行し、API経由でサーバーと通信するJavaScriptアプリ(例: React, Angular, Vue)。
  • Native Application: モバイルデバイスやデスクトップでネイティブに動作するアプリ(例: iOS, Android)。
  • Machine to Machine (M2M) Application: CLIツール、デーモン、IoTデバイスなど、ユーザーの介在なしにAPIアクセスを必要とする非対話型アプリケーション。

アプリケーションはAuth0ダッシュボードのApplications > Applicationsで登録・管理され、コールバックURL、許可されたオリジン、利用可能なグラントタイプなどの設定項目があります。

API (Resource Server): 保護対象リソース

Auth0におけるAPI(またはリソースサーバー)は、保護したいバックエンドサービスを表すエンティティとして登録されます。クライアントアプリケーションは、これらのAPIにアクセスするためのアクセストークンを要求します。

APIを定義することで、アプリケーションがユーザーの代わりにリソースにアクセスするために要求できるスコープ(Permission)を定めることができます。

APIを扱う際には、開発者が定義するAPIと、Auth0が提供するAPIを区別することが重要です。Auth0が提供するAPIは以下の通りです。

  • Authentication API: Auth0のアイデンティティ機能(ログイン、サインアップ、MFA、トークン要求、ユーザープロファイルアクセスなど)を公開します。通常、Auth0 SDK(例: auth0-spa-js )経由で利用されますが、カスタム認証UIを構築する場合は直接呼び出すこともあります。Auth0ダッシュボードのAPI一覧には表示されません。
  • Management API: Auth0アカウントのプログラムによる管理(ユーザー、アプリケーション、コネクションなどのCRUD操作)を可能にします。一覧取得APIはレスポンス件数に制限があり、それ以上の結果を取得するためにはページネーションパラメータが必要な場合や、一括出力ジョブを発行するAPIの利用が必要な場合があります。

コネクション (Connection): 認証方法

コネクションは、Auth0とユーザーソース(アイデンティティプロバイダ、IdP)との関係性を定義します。特に外部IdPとの接続の場合、Auth0がIdPとの間に介在することで、アプリケーションをIdPの実装変更から隔離する役割を果たします。

主なコネクションタイプは以下の通りです。

  • データベースコネクション: ユーザー認証情報(通常はメールアドレスとパスワード)をAuth0内に保存します(例: Username-Password-Authentication )。
  • ソーシャルコネクション: GoogleFacebook、X(旧Twitter)などのソーシャルIdPを介してユーザーを認証します。
  • エンタープライズコネクション: SAML(ADFS、Oktaなど)、OpenID Connect(OIDC)、Microsoft Entra ID、Google WorkspaceといったエンタープライズIdPとのフェデレーションを可能にします。(Auth0の契約プランによって作成数に制限があります。)
  • パスワードレスコネクション: メールやSMSで送信されるマジックリンクやコードを用いて認証します。

コネクションはAuth0ダッシュボードのAuthenticationセクションで設定され、特定のアプリケーションに対してコネクションを有効化したり、属性同期の設定を行ったりします。Management API経由でのコネクション作成も可能です。

エンタープライズコネクションはtoBユースケースに、ソーシャルコネクションとパスワードレスコネクションはtoCユースケースに特に向いています。

Actions: 認証フローのカスタマイズ

Actionsは、Auth0プラットフォーム内の特定のポイント(トリガー、例: ログイン後、ユーザー登録前)で実行される、テナント固有のセキュアでバージョン管理されたNode.js関数です。カスタムクレームの追加、MFAの強制、ユーザーのリダイレクト、外部APIの呼び出しなど、Auth0の機能をカスタマイズし拡張するために使用されます。

Actionsは、RulesやHooksの後継機能です。RulesとHooksは2024年11月18日にサポート終了(EOL)となり、2023年10月16日以降に作成された新規テナントでは利用できません。このため、Auth0の拡張機能を実装する際には、Actionsを採用することが推奨されます。

コアコンセプトのまとめ

これらのコアコンセプト(テナント、アプリケーション、API、コネクション、Actions)は独立して存在するのではなく、相互に関連し合っています。例えば、アプリケーションは特定のテナント内に存在し、認証のためにコネクションを利用し、保護されたAPIへのアクセスを要求します。

一つのテナントが複数のアプリケーションをホストし、各アプリケーションが異なるコネクションセット(例:あるアプリはデータベースとソーシャルログイン、別のアプリはエンタープライズSAML)を有効にすることも可能です。

またAuth0 Explorerのようなツールは、これらの関係性が複雑化する可能性があるために存在しており、自身のテナント構造を視覚化することで、設計段階での見落としを防ぐことに役立ちます。

表1: Auth0コアコンセプト概要

コンセプト名 説明 主な用途
テナント (Tenant) Auth0設定とアセット(アプリ、コネクション、ユーザー等)の管理単位。一意のドメインを形成。 環境分離(開発/ステージング/本番)、ユーザーグループ分離、ブランド分離。
アプリケーション (Application) Auth0で認証・認可を行うソフトウェアエンティティ(SPA, Web, Native, M2M)。 ユーザー認証、APIアクセス権限の要求。
API (Resource Server) 保護対象のバックエンドサービス。アクセストークンの対象(audience)となり、スコープ(権限)を定義。 バックエンドAPIの保護、認可制御。
コネクション (Connection) Auth0とユーザーソース(IdP:データベース、ソーシャル、エンタープライズ、パスワードレス)との連携。 ユーザー認証方法の提供。
Actions 認証フロー内の特定ポイントで実行されるNode.js関数。Rules/Hooksの後継。 カスタムクレーム追加、動的MFA、リダイレクト、外部API連携など、認証フローのカスタマイズと拡張。

Auth0環境構築の実践

Auth0のコアコンセプトを理解した上で、次に環境構築のステップに進みます。ここでは、テナント戦略、アプリケーション設定、API(リソースサーバー)定義という、Auth0導入の初期段階で重要となる要素について解説します。

テナント戦略:開発・ステージング・本番環境の分離

Auth0を利用するための最初のステップの一つは、適切なテナント戦略を立てることです。Auth0は、開発(Development)、ステージング(Staging)、本番(Production)といった環境ごとに個別のテナントを作成することを推奨しています。

この分離戦略には、以下の利点があります。

  • 環境の隔離: 各環境が独立しているため、開発テナントでの設定変更やActionsスクリプトのテストが、本番環境のユーザーや運用に影響を与えることはありません。これにより、安全な開発とテストサイクルが保証されます。
  • 設定の最適化: 環境ごとに異なる設定を適用できます。例えば、本番環境では厳格なセキュリティポリシーを適用し、開発環境ではデバッグを容易にするために設定を緩やかにするといった使い分けが可能です。Auth0のテナント設定では「Environment Tag」を指定でき、「Production」とタグ付けされたテナントは、他の環境(Development、Staging)よりも高いレート制限が付与されます。
  • SDLC(Software Development Life Cycle)のサポート: この分離は、一般的なSDLCプロセスと整合性が高く、各フェーズでの品質管理を容易にします。

ただし、複数のテナントを管理することは、テナント数が増えるにつれて複雑性が増す可能性も考慮に入れる必要があります。テナント名は一度作成すると変更できず、削除後の再利用も不可能なため、特に本番テナントの命名は慎重に行う必要があります。

必要な分離レベルと管理オーバーヘッドのバランスを考慮し、テナント数を決定することが求められます。このテナント戦略は、開発サイクルの効率性と本番環境の安定性・セキュリティに影響するため、プロジェクト初期段階での計画が求められます。

アプリケーション設定:種類と主要パラメータ

Auth0における「アプリケーション」は、認証・認可の対象となるソフトウェアエンティティです。前述の通り、SPA、Regular Web App、Native App、M2M Appといった種類があります。これらのアプリケーションは、Auth0ダッシュボードのApplications > Applicationsセクションで設定・管理されます。

アプリケーションにおける主要な設定項目は以下の通りです。

  • name : アプリケーションの名称。
  • description : アプリケーションの説明。
  • app_type : アプリケーションの種類 ( native , spa , regular_web , non_interactive )。
  • callbacks (Allowed Callback URLs): 認証成功後にAuth0がユーザーをリダイレクトする先のURLの配列。セキュリティ上重要で、ホワイトリスト形式で管理する必要があります。不正なリダイレクト先へのトークン漏洩を防ぐため、ワイルドカードの使用は慎重に行い、可能な限り具体的なURLを指定することが推奨されます。
  • allowed_origins (Allowed Web Origins): SPAなどがCORS(Cross-Origin Resource Sharing)リクエストやサイレント認証を行う際に許可されるオリジンのURL。これもセキュリティに関わる設定です。
  • allowed_logout_urls (Allowed Logout URLs): ログアウト後にリダイレクトを許可するURLのリスト。
  • grant_types : アプリケーションが利用を許可されるOAuth 2.0のグラントタイプ(例: authorization_code , client_credentials , refresh_token )。

特にcallbacksとallowed_originsの設定は、セキュリティの観点から重要です。これらのURLを不適切に設定すると、トークンが意図しない第三者に渡ってしまったり、オープンリダイレクト脆弱性を突かれたりする危険性があります。開発初期段階でhttp://localhost:PORTのようなローカル開発用URLを設定する場合でも、本番環境では必ず実際のドメインに基づいたセキュアなURLに更新する必要があります。

API(リソースサーバー)の定義と設定

Auth0におけるAPI(リソースサーバー)は、クライアントアプリケーションがアクセスしようとするバックエンドサービスやリソース群を表します。これらをAuth0に登録することで、アクセストークンによる保護対象として定義できます。

APIの定義は、Auth0ダッシュボードのApplications > APIsセクションで行います。主要な設定項目は以下の通りです。

  • name : APIの名称。
  • identifier (Audience): APIの一意な論理的識別子。これは重要で、発行されるアクセストークンの aud (audience) クレームの値として使用されます。API側は、受け取ったアクセストークンの aud クレームが自身の識別子と一致することを確認し、トークンがそのAPI向けに発行されたものであることを検証します。
  • signing_alg : アクセストークンを署名するためのアルゴリズム(例: RS256 (RSA署名 with SHA-256) が推奨されます)。
  • token_lifetime (Access Token Expiration): アクセストークンの有効期間。

さらに、APIに対してスコープ(Permissions)を定義できます。スコープは、APIが提供する機能やリソースへのアクセス権限を表現するものです(例: read:timesheets, create:timesheets)。クライアントアプリケーションは、ユーザーの同意を得てこれらのスコープを要求し、アクセストークンに含まれるスコープに基づいてAPIが認可判断を行います。

これらの設定を適切に行うことで、どのアプリケーションがどのAPIのどの操作を実行できるかを細かく制御し、セキュアなAPIアクセス管理を実現できます。

認証フローの実装:詳細ガイド

Auth0環境のセットアップが完了したら、次はアプリケーションへの認証フローの実装です。ここでは、適切な認証フローの選択、Auth0 SDKの活用、そして特にSPA(シングルページアプリケーション)におけるトークン管理とセッションのベストプラクティスについて詳しく解説します。

適切な認証フローの選択

Auth0は、様々なアプリケーションタイプとセキュリティ要件に対応するため、OIDC (OpenID Connect) および OAuth 2.0に基づいた認証フローをサポートしています。適切なフローを選択することは、アプリケーションのセキュリティとUXの両方にとって重要です。

主要な認証フローとその推奨ユースケースは以下の通りです。

  • Authorization Code Flow with PKCE (Proof Key for Code Exchange):
    • SPAやネイティブアプリケーション(モバイルアプリなど)に推奨されるフローです。
    • PKCEは、認可コードの横取り攻撃(Authorization Code Interception Attack)を緩和するためのセキュリティ拡張であり、クライアントシークレットを安全に保持できないパブリッククライアントに適しています。
  • Authorization Code Flow:
    • サーバーサイドで動作するウェブアプリケーション(例: Express.js, ASP.NET)に適しています。
    • これらのアプリケーションはクライアントシークレットを安全にバックエンドで保持できるため、このフローを利用できます。
  • Client Credentials Flow:
    • M2M (Machine-to-Machine) アプリケーション、つまりユーザーの介在なしにクライアントアプリケーション自体がAPIリソースへアクセスする場合に使用されます。CLIツールやバックエンドサービスなどが該当します。
  • Resource Owner Password Flow (ROPG):
    • ユーザーの認証情報(ユーザー名とパスワード)をクライアントアプリケーションが直接収集し、Auth0に送信するフローです。ユーザーの認証情報をクライアントが扱うためセキュリティリスクが高く、他のフローが利用できない特定のレガシーシナリオや信頼されたファーストパーティアプリケーションに限定して利用が検討されるべきです。一般的には非推奨です。
  • Implicit Flow with Form Post:
    • かつてはSPAで利用されていましたが、セキュリティ上の懸念から、現在ではAuthorization Code Flow with PKCEが推奨されています。

フロー選択の判断基準は、アプリケーションのタイプ(クライアントサイドかサーバーサイドか、ユーザーが介在するか否か)、クライアントシークレットを安全に保管できるか、そして求められるセキュリティレベルです。Auth0の公式ドキュメントには、「Which OAuth 2.0 Flow Should I Use?」といったガイダンスも提供されており、選択の助けとなります。

表2: 認証フロー選択ガイド

フロータイプ 主なユースケース セキュリティ特性 Auth0 SDKサポート
Authorization Code Flow with PKCE SPA、ネイティブアプリケーション(モバイル等) クライアントシークレット不要。認可コード横取り攻撃対策(PKCE)。パブリッククライアントに最適。 主要なSPA/Native SDK
Authorization Code Flow サーバーサイドウェブアプリケーション クライアントシークレットを安全にバックエンドで保持可能。 主要なWeb SDK
Client Credentials Flow M2M(Machine-to-Machine)アプリケーション(CLI、デーモン、バックエンドサービス等) アプリケーション自体が認証。ユーザー介在なし。 各言語向けSDK
Resource Owner Password Flow (ROPG) レガシーシステム連携、他のフローが利用不可能な特定ケース(限定的に使用) ユーザー認証情報をクライアントが直接扱うためセキュリティリスク高。ファーストパーティの信頼されたクライアントでのみ検討。一般的に非推奨。 API直接利用
Implicit Flow with Form Post (参考) (旧) SPA Authorization Code with PKCEに比べセキュリティ面で劣る。現在では非推奨。 (旧) SPA SDK

Auth0 SDKの活用(例:React SDKでの実装ポイント)

Auth0は、各種プログラミング言語フレームワーク向けにSDKを提供しており、これらを利用することでOAuth 2.0やOIDCの実装詳細を抽象化し、認証機能の組み込みを簡素化できます。

ここでは、SPAライブラリであるReact向けのSDK auth0-reactを例に、主要な実装ポイントを見ていきます。

  • 1. Auth0Provider の設定: アプリケーションのルートコンポーネントAuth0Provider でラップします。このプロバイダには、Auth0テナントの domain とアプリケーションの clientId を設定します。これらの値は通常、環境変数経由で渡されます。
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';

const rootElement = document.getElementById('root');
if (!rootElement) throw new Error('Failed to find the root element');

const root = ReactDOM.createRoot(rootElement);

root.render(
  <React.StrictMode>
    <Auth0Provider
      domain={process.env.REACT_APP_AUTH0_DOMAIN!}
      clientId={process.env.REACT_APP_AUTH0_CLIENT_ID!}
      authorizationParams={{
        redirect_uri: window.location.origin,
        // audience: process.env.REACT_APP_AUTH0_AUDIENCE,
      }}
    >
      <App />
    </Auth0Provider>
  </React.StrictMode>
);
  • 2. 認証機能の利用: useAuth0 フックを利用することで、コンポーネント内から認証関連の関数や状態( loginWithRedirect , logout , isAuthenticated , user , getAccessTokenSilently など)にアクセスできます。
// MyComponent.tsx
import React from 'react';
import { useAuth0, User } from '@auth0/auth0-react';

const MyComponent: React.FC = () => {
  const { 
    loginWithRedirect, 
    logout, 
    user, 
    isAuthenticated, 
    isLoading, 
    getAccessTokenSilently 
  } = useAuth0<User>();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  const callApi = async () => {
    try {
      const token = await getAccessTokenSilently({
        authorizationParams: {
          audience: 'YOUR_API_IDENTIFIER', // APIのIdentifier
          // scope: 'read:messages', // 必要なスコープ
        }
      });
      // API呼び出し時にtokenをAuthorizationヘッダーに含める
      const response = await fetch('YOUR_API_ENDPOINT', {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
      const data = await response.json();
      console.log(data);
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <div>
      {!isAuthenticated && <button onClick={() => loginWithRedirect()}>Log In</button>}
      {isAuthenticated && user && (
        <div>
          <h2>Welcome, {user.name}</h2>
          <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}>
            Log Out
          </button>
          <button onClick={callApi}>Call Protected API</button>
        </div>
      )}
    </div>
  );
};

export default MyComponent;
  • 3. ルートの保護: withAuthenticationRequired 高次コンポーネント (HOC) を使用するか、 isAuthenticated の状態をチェックすることで、認証済みユーザーのみがアクセスできるルートを保護します。
// ProtectedRoute.tsx
import React, { ComponentType } from 'react';
import { withAuthenticationRequired, AppState, WithAuthenticationRequiredOptions } from '@auth0/auth0-react';
import MyProtectedComponent from './MyProtectedComponent'; // 保護したいコンポーネント

const ProtectedRoute: React.FC = () => {
  return <MyProtectedComponent />;
};

const options: WithAuthenticationRequiredOptions = {
  onRedirecting: () => <div>Redirecting you to the login page...</div>,
  // onAuthenticated: (appState?: AppState) => { /* 認証後の追加処理 */ },
};

// withAuthenticationRequiredでラップすると、未認証の場合はログインページにリダイレクトされる
export default withAuthenticationRequired(ProtectedRoute, options);

Auth0 SDKを利用することで、開発者は認証プロトコルの実装から解放され、アプリケーション固有のロジック開発に集中できます。しかし、SDKが内部でどのようなフローを実行しているのか(例えば、なぜPKCEが使われるのか、サイレント認証はどのように機能するのか)を理解しておくことは、問題発生時のトラブルシューティングや、カスタマイズを行う際に役立ちます。

auth0-reactライブラリは内部でauth0-spa-jsライブラリを利用しているため、必要に応じてコードを参照すると理解が深まります。

コールバック処理、トークン管理とセッション (SPAにおけるベストプラクティス)

SPAにおける認証では、認証後のコールバック処理、取得したトークンの安全な管理、そしてセッションの維持が重要な課題となります。

  • コールバックURLの処理:
    • 認証が成功すると、Auth0はユーザーをアプリケーション設定で指定されたコールバックURLにリダイレクトします。この際、URLのクエリパラメータやフラグメントに認可コードやトークンが含まれています。Auth0 SDKは通常、これらの情報を自動的にパースし、トークンを取得・保存する処理を行います。
  • トークンストレージ (SPA):
    • auth0-spa-js のようなAuth0のSPA向けSDKは、デフォルトでは取得したトークンをメモリ内に保存します。これはセキュリティ上は比較的安全ですが、ページリフレッシュやブラウザタブを跨いでの永続性がありません。
    • 永続性を持たせるために、SDKの設定でトークンをローカルストレージ ( localStorage ) に保存するよう変更できます。しかし、ローカルストレージはXSSクロスサイトスクリプティング)攻撃に対して脆弱であり、もし攻撃者がSPA内でJavaScriptを実行できた場合、保存されているトークンを窃取されるリスクがあります。このため、ローカルストレージの使用は慎重に検討し、XSS対策を徹底する必要があります。
    • アクセストークンは短命にし、リフレッシュトークンを利用して新しいアクセストークンを取得する戦略が一般的です。
  • トークンの有効期限と更新 (サイレント認証):
    • アクセストークンはセキュリティのために有効期間が短く設定されています。SPAでは、ユーザーに再認証を強いることなくアクセストークンを更新する仕組みが必要です。
    • サイレント認証 ( prompt=none ) は、ユーザーがAuth0上でアクティブなセッションを持っている場合に、ユーザーの操作なしに新しいトークンを取得するメカニズムです。これは隠しiframe内で実行されるか、リフレッシュトークンを利用して行われます。
    • auth0-spa-js SDKでは、 getTokenSilently() メソッドがこの処理を担当します。
    • リフレッシュトークンローテーション (Refresh Token Rotation) は、SPAでリフレッシュトークンをより安全に利用するための推奨プラクティスです。リフレッシュトークンが使用されるたびに新しいリフレッシュトークンが発行され、古いものは無効化されるため、トークン漏洩時のリスクを低減できます。また、ブラウザのサードパーティCookie制限によるサイレント認証の問題を回避するのにも役立ちます。
  • セッション管理:
    • Auth0は独自のセッションをサーバー側で管理します。SPA側のSDKは、Auth0のセッション状態に基づいてローカルアプリケーションのセッション(ユーザーがログインしているかどうかの状態)を管理するのを助けます。

SPAにおけるトークン管理は、利便性とセキュリティのバランスを取る必要があり、特にトークンの保存場所と更新戦略は慎重な設計が求められます。Auth0 SDKのデフォルト動作を理解し、アプリケーションの要件に合わせて適切に設定することが、安全でスムーズなUXを実現する鍵となります。

Auth0 Actionsによる認証フローの拡張

Auth0 Actionsは、認証・認可フローの様々な段階でカスタムロジックを実行するための機能です。従来のRulesやHooksに代わる拡張メカニズムとして位置づけられており、より柔軟で開発者フレンドリーな方法でAuth0の動作をカスタマイズできます。

Actionsの一般的なユースケースとコード例

Actionsを利用することで、認証フローの中にカスタムロジックを組み込むことができます。

  • JWTへのカスタムクレーム追加:
    • IDトークンやアクセストークンに、デフォルトでは含まれない情報(例: ユーザーのロール、Permission、user_metadata からのカスタム属性、外部システムから取得した情報など)を追加します。これには、Login / Post Loginトリガーで api.idToken.setCustomClaim()api.accessToken.setCustomClaim() メソッドを使用します。
    • 標準OIDCクレームとの衝突を避けるため、カスタムクレームには必ず名前空間を使用することが推奨されます(例: https://myapp.example.com/roles)。
// Login / Post Login Action
exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://myapp.example.com/'; // 自身が管理するURLを名前空間として使用
  if (event.user.user_metadata && event.user.user_metadata.favorite_color) {
    api.idToken.setCustomClaim(namespace + 'favorite_color', event.user.user_metadata.favorite_color);
  }
  if (event.authorization && event.authorization.roles) {
     api.idToken.setCustomClaim(namespace + 'roles', event.authorization.roles);
     api.accessToken.setCustomClaim(namespace + 'roles', event.authorization.roles);
  }
};
  • 動的なMFAトリガー(例: ユーザー属性やコンテキストに基づく):
    • ユーザーのロール、アクセス元のIPアドレス、アクセスしようとしているアプリケーションなどのコンテキスト情報に基づいて、動的にMFAを要求したりスキップしたりします。Login / Post Login トリガーで api.multifactor.enable("any", { allowRememberBrowser: false }); や特定のファクターを指定してMFAを有効化したり、 api.multifactor.enable("none"); でMFAをスキップしたりできます。
// Login / Post Login Action
exports.onExecutePostLogin = async (event, api) => {
  // 特定のクライアントID(アプリケーション)の場合のみMFAを要求
  if (event.client.client_id === 'YOUR_SENSITIVE_APP_CLIENT_ID') {
    api.multifactor.enable("any", { allowRememberBrowser: false });
  }

  // パスキーで認証した場合はMFAをスキップ
  const usedPasskey = event.authentication?.methods.some(
    (method) => method.name === "passkey"
  );
  if (usedPasskey) {
    api.multifactor.enable("none"); 
  }
};
  • 外部API連携によるリスクベース認証:
    • ログイン試行のリスクを評価するために外部のAPI(例: 不正検知サービス、IPレピュテーションサービス)を呼び出し、その結果(リスクスコアなど)に基づいてMFAを動的に要求したり、アクセスを拒否したりします。 Login / Post Login トリガー内で、 fetchaxios(npm依存関係として追加)などのHTTPクライアントを使用して外部APIを呼び出します。APIキーなどの秘匿情報はActionのSecretsに保存します ( event.secrets )。
// Login / Post Login Action (axiosを依存関係として追加する必要あり)
const axios = require("axios"); 

exports.onExecutePostLogin = async (event, api) => {
  try {
    const riskApiUrl = event.secrets.RISK_API_URL; // ActionのSecretに設定
    const riskApiKey = event.secrets.RISK_API_KEY; // ActionのSecretに設定

    const response = await axios.post(riskApiUrl, {
      ip_address: event.request.ip,
      user_agent: event.request.user_agent,
      email: event.user.email
      // その他リスク評価に必要な情報を送信
    }, { 
      headers: { 
        'Authorization': `Bearer ${riskApiKey}`,
        'Content-Type': 'application/json'
      } 
    });

    const riskScore = response.data.score; // APIのレスポンス形式に合わせて調整

    if (riskScore > 0.8) { // 高リスク
      api.access.deny("高リスクのためログイン試行はブロックされました。");
    } else if (riskScore > 0.5) { // 中リスク
      api.multifactor.enable("any", { allowRememberBrowser: false });
    }
    // 低リスクの場合はそのままログインを許可 (何もしない)
  } catch (error) {
    console.error("リスク評価APIの呼び出し中にエラーが発生しました:", error.message);
    // エラー発生時のフォールバック処理: 例えば、アクセスを拒否するか、デフォルトでMFAを要求する
    api.access.deny("リスク評価に失敗しました。ログインは拒否されました。");
  }
};

Actionsは、静的な認証ルールを超えて、リアルタイムのコンテキストに基づいた動的で詳細なセキュリティポリシーやUXのカスタマイズを実現するツールです。ただし、npmパッケージの依存関係やSecretsの管理には注意が必要です。

信頼できるパッケージの選定、バージョン管理、そしてSecretsの安全な取り扱いは、認証フロー全体のセキュリティを維持するために必要です。

ユーザー管理とID連携

Auth0を導入する上で、ユーザープロファイルの管理方法と、既存の社内システムや外部のアイデンティティプロバイダ(IdP)との連携は重要な要素となります。ここでは、Auth0におけるユーザープロファイルの構造、外部IdPとの連携方法、そして既存ユーザーデータの移行戦略について解説します。

ユーザープロファイル:user_metadataapp_metadataの使い分け

Auth0は、IdPから取得される属性情報を扱うために、正規化されたユーザープロファイルスキーマを提供しています。このプロファイルには標準的な属性(例: email, name, pictureなど)に加えて、カスタムデータを格納するためのメタデータフィールドが用意されています。

主要なメタデータタイプは以下の2つです。

  • user_metadata:
    • ユーザーの嗜好(例: 好みの言語、テーマカラー)など、アプリケーションのコア機能に直接影響を与えない情報を格納します。
    • ユーザー自身が(Management API経由で構築されたUIを通じて)編集可能なデータと位置づけられます。
    • セキュアなデータストアとして使用すべきではありません。
    • サインアップエンドポイント経由では、最大10個の文字列フィールド、各500文字までという制限があります。
  • app_metadata:
    • ユーザーのアクセス権限に影響を与える情報(例: ロール、Permission、所属部署、顧客プラン、外部システムIDなど)を格納します。
    • ユーザー自身は編集できず、管理者やシステム(Actionsなど)によって管理されるデータです。

この他に、アプリケーション(クライアント)自体の情報を格納するclient_metadataも存在します。

メタデータ利用時のベストプラクティス:

  • 機密情報の回避: 個人を特定できる情報(PII)の中でも特に機微な情報(例: 社会保障番号、クレジットカード番号)はメタデータに保存すべきではありません。
  • 命名規則: フィールド名に . (ドット) や $ (ドル記号) を含めることはできません。
  • サイズ制限: ユーザーごとにインデックス化およびクエリ可能なメタデータには1MBのサイズ制限があります。これを超えると検索や取得に影響が出る可能性があります。
  • パフォーマンス: メタデータは強力ですが、大きなデータや複雑なネスト構造を持つデータ、頻繁な更新を伴うデータを格納すると、検索時のパフォーマンスに影響を与える可能性があります。マーケティングリサーチのような大量データ分析には不向きです。そのような場合は、外部システムにデータを保持し、Auth0にはそのポインタ(ユーザーIDなど)のみを格納する方が好ましいです。
  • 適切な使い分け: user_metadataapp_metadataの役割を区別し、アクセス制御に関わる情報はapp_metadataに格納することが、セキュリティと管理の観点から必要です。

表3: メタデータタイプ比較 (user_metadata vs app_metadata)

メタデータタイプ 説明 ユーザー編集可否 主な用途/格納する情報例 注意点
user_metadata ユーザーの嗜好など、コア機能に影響しない属性を格納。 可(UI構築が必要) 好みの言語、テーマ、通知設定、住所(公開情報として)、趣味など。 セキュアなデータストアではない。機密情報(特にアクセス制御に関わるもの)の保存は避ける。サインアップ時のフィールド数・文字数制限あり。
app_metadata ユーザーのアクセス権限に影響する情報を格納。 不可 ロール、Permission、所属部署、顧客プラン、外部システムID、アクセス制御グループなど。 ユーザーによる編集は不可。アクセス制御ロジックの判断基準となる情報を格納。機微なPIIの保存は推奨されない。フィールド名やサイズ制限に注意。

外部IdPとの連携:Social Login, Enterprise (SAML/OIDC)

Auth0の大きな利点の一つは、外部IdPと連携できることです。これにより、ユーザーは既存のアカウントを利用してアプリケーションにログインできます。

  • ソーシャルコネクション (Social Login):
    • Google, Facebook, X (旧Twitter) といった一般的なソーシャルプロバイダ経由でのログインを設定できます。これらのプロバイダから取得されるユーザープロファイル属性は、デフォルトではログインごとにAuth0のユーザープロファイルと同期されますが、この同期タイミングは設定で変更可能です(例: 初回ログイン時のみ同期)。
  • エンタープライズコネクション (SAML):
  • エンタープライズコネクション (OIDC):
    • 外部のOIDC IdPとも連携できます。設定には、IdPのOIDCディスカバリーURL、クライアントID、クライアントシークレットなどが必要です。Auth0は、OIDCコネクションの場合、デフォルトではIdPの /userinfo エンドポイントを呼び出さず、ユーザー情報をIDトークン内に期待する点に注意が必要です。OIDC IdPからの属性マッピングも、ユーザーマッピングテンプレートなどを利用して設定します。

外部IdPとの連携において、IdPから渡される属性名がAuth0の期待する形式と異なる場合や、特定の属性(例: 部署名、役職、グループメンバーシップ)をAuth0プロファイルの特定フィールド(特にapp_metadata)に格納したい場合、属性マッピングの設定が必要です。SAMLコネクションでは「Mappings」タブ、OIDCコネクションでは「User Mapping」セクションなどで設定を行います。

連携に問題が発生した場合は、IdPが実際にどのような属性をどのような名前で送信してくるかを確認するために、実際のSAMLアサーションやOIDCトークンを調査することがトラブルシューティングの鍵となります。

既存ユーザーデータの移行戦略(自動移行、一括ユーザーインポート)

既存のユーザーデータベースからAuth0へユーザーデータを移行するには、二つの戦略があります。

  • 自動移行 (Automatic Migration / Trickle Migration / Lazy Migration):
    • この方法では、ユーザーが新しいAuth0ベースのシステムに初めてログインしようとした際に、バックグラウンドで旧システムからAuth0へユーザーデータが移行されます。
    • Auth0のカスタムデータベースコネクション機能を利用し、「Import Users to Auth0」オプションを有効にします。 LoginGet User といったデータベースアクションスクリプトを実装し、これらのスクリプトが旧データベースに接続してユーザー認証情報を検証したり、ユーザープロファイルを取得したりします。認証が成功すると、Auth0はユーザープロファイルを自身のデータストアに作成(インポート)します。
    • この方法の利点は、ユーザーにパスワードリセットを強いることなく、シームレスに移行を進められる点です。ただし、移行期間中は旧データベースへのアクセスが必要となります。
  • 一括ユーザーインポート (Bulk User Imports):
    • Auth0 Management API/post_users_imports エンドポイントや、User Import/Export Extensionを利用して、既存ユーザーデータを一括でAuth0にインポートします。
    • ユーザーデータはJSON形式で準備する必要があり、各ユーザーオブジェクトはAuth0のスキーマ要件に従う必要があります。1ファイルあたりのサイズ制限(例: 500KB)があるため、大規模なユーザーベースの場合はデータを分割して複数のジョブとして実行します。
    • パスワードハッシュも、Auth0がサポートするアルゴリズム(例: bcrypt)であればインポート可能です。ただし、Auth0は平文のパスワードをエクスポートする機能は提供していません。互換性のないハッシュアルゴリズムの場合や平文パスワードが利用できない場合は、ユーザーにパスワードリセットを促すか、自動移行と組み合わせて旧パスワードでの認証を一時的に許可するなどの対応が必要です。

移行戦略を選択する際には、ダウンタイムの許容度、UXへの影響、旧システムのパスワードハッシュの互換性、プロジェクトのタイムラインなどを総合的に考慮する必要があります。多くの場合、初期のユーザー群に対して自動移行を適用し、一定期間後に残りの非アクティブユーザーを一括ユーザーインポートするという組み合わせ戦略も有効です。

いずれの戦略を採るとしても、旧システムとAuth0間でのデータマッピング(特にuser_idやカスタム属性)の正確性が求められます。

セキュリティ強化のポイント

Auth0を導入する際には、提供される機能を活用してセキュリティを高めることが必要です。多要素認証(MFA)の設定、バックエンドでのトークン検証、Attack Protectionの活用は、アプリケーションとユーザーデータを保護するための柱となります。

MFA(多要素認証)の設定:Push通知, TOTP, SMS

多要素認証(MFA)は、パスワードだけに依存しない追加の認証レイヤーを提供し、アカウント乗っ取りのリスクを低減します。Auth0は複数のMFAファクターをサポートしています。

  • Push通知 (Auth0 Guardian):
    • ユーザーがログイン試行を行うと、事前に登録されたモバイルデバイス上のAuth0 Guardianアプリ(またはGuardian SDKを組み込んだカスタムアプリ)にプッシュ通知が送信されます。ユーザーは通知上で「許可」または「拒否」をタップするだけで認証を完了できます。UXとセキュリティのバランスが良いとされています。
  • ワンタイムパスワード (OTP/TOTP):
    • Google AuthenticatorやAuthyといった認証アプリを使用して、時間ベースのワンタイムパスワード(TOTP)を生成します。ユーザーはこの生成されたコードを入力して認証を行います。オフラインでも利用可能で、堅牢な認証方法です。
  • SMS/Voice通知:
    • ユーザーの登録済み電話番号にSMSまたは音声通話でワンタイムコードを送信します。利便性は高いですが、SIMスワッピング攻撃などのリスクも指摘されており、他のファクターとの併用や、高セキュリティが求められる場面では検討が必要です。Auth0のデフォルトSMSプロバイダはテスト用途に限られ、本番環境ではTwilioのような外部プロバイダやカスタムプロバイダの設定が推奨されます。

これらのMFAファクターは、Auth0ダッシュボードのSecurity > Multi-factor Authセクションで設定・有効化できます。Auth0 Actionsを利用することで、ユーザーのロールやアクセスコンテキストに基づいて動的にMFAを要求するような制御も可能です(詳細は「Auth0 Actionsによる認証フローの拡張」の章を参照)。

MFAファクターの選択は、対象ユーザー層、アプリケーションの性質、求められるセキュリティレベル、そしてユーザビリティを考慮して決定すべきです。

表4: MFA要素比較

要素 仕組み 設定時の考慮点 UXインパク セキュリティ強度
Push通知 (Auth0 Guardian) ログイン試行時に登録デバイスのGuardianアプリ等に通知を送信し、ユーザーが許可/拒否を選択。 GuardianアプリのインストールまたはSDKの組み込みが必要。ネットワーク接続必須。 低(通知をタップするだけで簡単)。 高(デバイス自体が認証要素、フィッシング耐性あり)。
TOTP (認証アプリ) 時間同期されたワンタイムパスワードを認証アプリで生成・入力。 ユーザーによる認証アプリのセットアップが必要。オフラインでも利用可能。 中(アプリ起動とコード入力の手間)。 高(コードは短時間で変化、フィッシングに強い)。
SMS/Voice通知 登録電話番号にSMSまたは音声通話でワンタイムコードを送信し、ユーザーが入力。 SMSプロバイダ(Twilio等)の設定推奨(Auth0デフォルトはテスト用)。SIMスワッピングのリスク。電話番号の正確な登録が必要。ネットワーク接続必須。 中(コード受信と入力の手間)。 中~高(SMSはフィッシングやSIMスワッピングに脆弱な可能性あり。Voiceは比較的安全性が高いが利便性はSMSに劣る場合がある)。

トークン検証のベストプラクティス(バックエンド側)

クライアントアプリケーションからアクセストークンを受け取ったバックエンドAPIは、そのトークンを無条件に信頼してはなりません。トークンが改ざんされていないか、意図した発行者からのものか、そしてそのAPI自身を対象としているかなどを検証する必要があります。この検証を怠ると、セキュリティ脆弱性につながります。

主要な検証項目は以下の通りです。

  1. 署名の検証 (Signature Verification): トークンがAuth0によって正しく署名されていることを確認します。これには、Auth0テナントのJWKS (JSON Web Key Set) URI ( https://{yourDomain}/.well-known/jwks.json ) から取得した公開鍵を使用します。
  2. 発行者の検証 (Issuer ( iss )): トークンの iss クレームが、自身のAuth0テナントのドメインと一致することを確認します。
  3. 対象者の検証 (Audience ( aud )): トークンの aud クレームに、APIの識別子(API設定時に指定したIdentifier)が含まれていることを確認します。これは、トークンがそのAPI向けに発行されたものであることを保証する上で重要です。
  4. 有効期限の検証 (Expiration (exp)): トークンのexpクレームをチェックし、トークンが有効期限切れでないことを確認します。また、 iat (Issued At) や nbf (Not Before) クレームも考慮に入れる場合があります。

これらの検証処理は、手動で実装するのではなく、各バックエンド言語向けに提供されている信頼できるJWTライブラリ(例: Javaの場合はjava-jwt、Node.js/Expressの場合はexpress-oauth2-jwt-bearerなど)を利用することが推奨されます。Auth0のバックエンド向けSDKやクイックスタートの多くは、これらの検証を自動的に行う機能を含んでいます。

Attack Protectionの活用

Auth0はAttack Protection機能を提供し、悪意のあるアクティビティからユーザーを保護します。

  • Bot Detection(ボット検知): 自動化されたボットによる不正アクセスやアカウント作成の試みを検知・軽減します。
  • Suspicious IP Throttling(不審なIPスロットリング): 1つのIPアドレスから複数のユーザーアカウントに対して行われる攻撃から防御します。
  • Brute-force Protection(総当たり攻撃防御): 1つのユーザーアカウントを対象にした総当たり攻撃を防ぎます。短時間に多数の不正なパスワード試行を検知し、該当アカウントやIPアドレスからのアクセスをブロックします。
  • Breached Password Detection(パスワード漏洩検知): ユーザーのパスワードが、データ漏洩で流出したことが知られているものと一致しないかをチェックします。

これらのAttack Protection機能は、Auth0ダッシュボードのSecurity > Attack Protectionから設定できます。Auth0の契約プランによって利用できる機能が変わりますが、テナントのセキュリティレベルを向上させるためにできるだけ活用すべきです。

高度なシナリオと導入時の考慮点

Auth0は基本的な認証・認可機能に加えて、複雑な要件に対応するための機能も提供しています。ここでは、マルチテナントアーキテクチャ、マイクロサービス環境での利用、ユーザーアカウントのリンク、カスタムデータベース連携といったシナリオについて、Auth0をどのように活用できるか、そしてその際の考慮点を解説します。

マルチテナントアーキテクチャ:Auth0 Organizationsの活用

マルチテナンシーとは、単一のソフトウェアインスタンスで複数の顧客グループ(テナント)に分離されたサービスを提供するアーキテクチャです。B2B SaaSアプリケーションなどでは一般的な要件となります。

Auth0でマルチテナンシーを実現する上で推奨される方法は、Auth0 Organizations機能を利用することです。

  • Auth0 Organizationsの概要: 単一のAuth0テナント内で、複数のビジネス顧客(組織)を管理できます。各組織に対して、独自のブランド設定(ログインページやメールテンプレートのカスタマイズ)、IdPフェデレーション(顧客自身のSAML IdPやOIDC IdPとの連携)、ロールベースのアクセス制御(RBAC)などを個別に設定可能です。これにより、顧客ごとに最適化された認証体験を提供しつつ、運用管理は一元的に行うことができます。
  • 利点:
    • 単一Auth0テナントでの集中管理による運用効率の向上。
    • 組織ごとの柔軟なカスタマイズ(ブランディング、IdP接続、ロール)。
    • ユーザーは複数の組織に所属可能。
  • ユースケース: 複数の企業顧客にサービスを提供するB2B SaaSアプリケーションで、各顧客企業が独自の認証要件(例: 自社のADFSとの連携、自社ブランドのログイン画面)を持つ場合など。

Auth0 Organizations以外の選択肢:

  • 複数のAuth0テナント: アプリケーションのテナントごとに個別のAuth0テナントを作成する方法。最大限の分離(データ、設定、レート制限など)を提供しますが、管理の複雑性が増大し、異なるAuth0テナント間のSSOは機能しません。厳格なデータ分離要件や、製品ラインごとの完全な独立性が求められる場合に検討されます。
  • ユーザープロファイルのメタデータにテナント情報を格納: 各ユーザーの app_metadata にテナントIDなどを格納し、認証後のトークンに含まれるその情報をもとに、アプリケーション側で表示や権限を制御する方法です。実装が比較的シンプルですが、テナントごとの細かいカスタマイズ(独自のIdP接続やログイン画面のブランディングなど)には対応できません。また、認可ロジックがアプリケーション側に集中し、複雑化しやすいという欠点もあります。

Auth0 Organizationsは、多くのB2Bマルチテナントシナリオにおいて最適なバランスを提供しますが、その適用範囲を正しく理解することが重要です。主に外部の顧客企業を「組織」として管理するための機能であり、社内の部署分離のような用途には、ロールベースアクセス制御など他のアプローチが適切な場合があります。

弊社ではAuth0 Organizationsの利用を検討した結果、ユースケースに合わないとして採用しないことになりました。

表5: Auth0におけるマルチテナンシーアプローチ比較

アプローチ 主な特徴 Pros Cons 最適なユースケース
Auth0 Organizations 単一Auth0テナント内で複数の顧客組織を管理。組織ごとのブランディング、IdP連携、ロール設定が可能。 集中管理、運用効率、組織ごとの柔軟なカスタマイズ、ユーザーは複数組織に所属可能。 最大限のデータ分離は提供しない。主にB2B SaaS向け。 複数の企業顧客にサービスを提供するB2B SaaSアプリケーション。各顧客が独自の認証要件を持つ場合。
複数のAuth0テナント アプリケーションテナントごとに個別のAuth0テナントを作成。 完全なデータ・設定分離、レート制限分離、ブランド分離。 管理の複雑性増大、テナント間SSO不可、ライセンスコスト増の可能性。 厳格なデータ主権・コンプライアンス要件、製品ラインごとの完全なブランド・機能分離が必要な場合。
ユーザープロファイルのメタデータにテナント情報を格納 app_metadata 等にテナントIDを格納し、アプリケーション側でロジック分岐。 実装が比較的シンプル。単一Auth0テナントで運用可能。 カスタマイズ性(ブランディング、IdP連携)に限界。認可ロジックが複雑化する可能性。スケーラビリティに課題が生じることも。 非常に小規模なマルチテナント、またはテナントごとのカスタマイズ要件が限定的な場合。

マイクロサービスアーキテクチャにおけるAuth0

マイクロサービスアーキテクチャでは、アプリケーションが独立してデプロイ可能なサービスの集合として構築されます。Auth0は、このようなアーキテクチャにおける認証・認可を効果的にサポートします。

  • APIゲートウェイパターン: 一般的に、APIゲートウェイがクライアントからのリクエストの単一エントリーポイントとして機能し、認証・認可処理(アクセストークンの検証など)を一元的に担った上で、内部マイクロサービスへリクエストをルーティングします。Auth0は、このAPIゲートウェイ自体を保護し、ゲートウェイが受け取るアクセストークンを発行・検証する役割を果たします。
  • トークンベース認証: 各マイクロサービスは、Auth0が発行したJWT形式のアクセストークンを検証することで、リクエスト元を認証し、アクセス権限を確認します。
  • Auth0エンティティの分離:
    • クライアントアプリケーション(SPA、ウェブアプリ、モバイルアプリなど)は、Auth0の「アプリケーション」として登録します。
    • バックエンドの各マイクロサービス(または論理的なサービスグループ)は、Auth0の「API(リソースサーバー)」として登録します。これにより、各APIに対して独自の識別子(Audience)とスコープ(権限)を定義できます。
  • 認可: Auth0 APIで定義されたスコープは、マイクロサービスの特定のエンドポイントや操作へのアクセス権限を制御します。APIゲートウェイまたは個々のマイクロサービスが、受け取ったアクセストークンに含まれるスコープを検証し、認可判断を行います。

マイクロサービス環境でAuth0を効果的に利用する鍵は、各API(リソースサーバー)の適切な定義(特にAudienceの一意性)と、各サービスにおけるトークン検証(Audience、Issuer、Scope、Signature、Expirationの確認)です。単にAuth0からトークンを取得するだけでは不十分で、各マイクロサービスが信頼できるゲートキーパーとして機能する必要があります。

ユーザーアカウントのリンクの実装

ユーザーアカウントのリンクは、一人のユーザーが持つ複数の異なるアイデンティティ(例: データベースアカウントとGoogleアカウント、異なるソーシャルアカウントなど)を、Auth0内の単一のプライマリーユーザープロファイルに紐付ける機能です。

  • 仕組み: ユーザーアカウントのリンクを実行すると、セカンダリアカウントの情報がプライマリアカウントの identities 配列内に埋め込まれます。プライマリアカウントの user_idメタデータuser_metadata , app_metadata )が保持され、セカンダリアカウントのメタデータは破棄されます(必要であれば手動でのマージが必要)。
  • 実装方法:
    • ユーザー主導のアカウントリンク (User-initiated account linking): アプリケーションのUI(例: プロファイルページの「アカウントをリンク」ボタン)を通じてユーザーが明示的にアカウントをリンクします。これには、Management APIの適切なエンドポイント(例: /api/v2/users/{primary_user_id}/identities )を、適切なスコープ( update:current_user_identities または update:users )を持つアクセストークンと共に呼び出す必要があります。
    • 提案型のアカウントリンク (Suggested account linking): アプリケーションが、例えば同一メールアドレスを持つ複数のアカウントを検出し、ユーザーにアカウントリンクを提案します。
    • Auth0 Actionsと外部アカウントリンクアプリ: より複雑なシナリオでは、Auth0 Actionsと専用のアカウントリンクアプリケーションを組み合わせて実装することも可能です。
  • ユースケース: 複数のログイン方法を提供しつつユーザープロファイルを一元化したい場合や、既存ユーザーが新しいログイン方法(例: ソーシャルログイン)を追加できるようにする場合などに有効です。

セキュリティ上の注意点として、アカウントをリンクする際には、両方のアカウントでユーザーが認証済みであることを確認し、特に手動でのアカウントリンクではユーザーに認証情報の再入力を求めることが推奨されます。

弊社では、エンタープライズコネクション(SSO)の機能を提供する際に、ユーザーアカウントのリンクの機能があることでユーザーの利便性が上がると思われたため、これを実装しました。

カスタムデータベース連携とデータ同期

既存の外部ユーザーデータベースをAuth0のアイデンティティプロバイダとして利用したい場合、Auth0のカスタムデータベースコネクション機能が役立ちます。

  • 仕組み: カスタムデータベースコネクションでは、Auth0が外部データベースとやり取りするために実行するJavaScriptアクションスクリプトLogin , Get User , Create , Verify , Change Password , Delete など)を定義します。例えば Login スクリプトは、ユーザーが入力した認証情報を外部データベースに問い合わせて検証し、成功すればユーザープロファイルをAuth0の正規化された形式で返します。
  • データ移行・同期オプション:
    • 自動移行 (Trickle Migration): カスタムデータベースコネクションの設定で「Import Users to Auth0」を有効にすると、ユーザーがカスタムデータベース経由で正常にログインするたびに、そのユーザーのプロファイルがAuth0の内部ストアに移行(コピー)されます。これにより、徐々にAuth0への依存度を高め、最終的には外部データベースへの依存をなくすことができます。
    • 移行なし(常に外部DBを参照): 「Import Users to Auth0」を無効にすると、Auth0は常にカスタムデータベーススクリプトを実行して外部データベースに問い合わせます。
  • スクリプト例: Auth0はMySQLなど主要なデータベース向けのスクリプトテンプレートを提供しています。これらのテンプレートを基に、自身のデータベーススキーマや認証ロジック(例: パスワードハッシュの比較に bcrypt を使用)に合わせてカスタマイズします。

カスタムデータベース連携は、既存のユーザー資産を活かしつつAuth0の高度な機能を利用可能にする手段ですが、スクリプトの正確な実装と、外部データベースとのネットワーク接続性・セキュリティ確保が重要となります。

開発と運用のヒント

Auth0の導入プロジェクトを成功させるためには、開発段階での効率的なセットアップと、運用開始後の安定稼働を見据えた準備が重要です。ここでは、ローカル開発環境の構築、デバッグ手法、CI/CDの導入、そしてログ収集とモニタリングに関するヒントを提供します。

ローカル開発環境のセットアップ(コールバックURL、許可オリジン)

Auth0はクラウドサービスですが、アプリケーション開発の多くはローカル環境で行われます。この際に注意すべき設定がいくつかあります。

  • コールバックURL ( Allowed Callback URLs ): Auth0は認証成功後、ユーザーをこのURLにリダイレクトします。ローカル開発時には、 http://localhost:PORT/callback のような形式のURL( PORT は開発サーバーのポート番号)をAuth0アプリケーション設定の「Allowed Callback URLs」に登録する必要があります。Auth0がこのURLに直接アクセスするわけではなく、ブラウザがリダイレクトされる先です。
  • 許可されたウェブオリジン ( Allowed Web Origins ): SPA(シングルページアプリケーション)の場合、CORS(Cross-Origin Resource Sharing)リクエストやサイレント認証(トークン更新)のために、ローカル開発サーバーのオリジン(例: http://localhost:PORT )を「Allowed Web Origins」に登録する必要があります。
  • 許可されたログアウトURL ( Allowed Logout URLs ): ログアウト後にリダイレクトさせたいローカルURLがある場合、同様に「Allowed Logout URLs」に登録します。
  • SDKの設定: Auth0 SDK(例: auth0-react , auth0-spa-js )を使用する場合、SDKの初期化時に正しいAuth0ドメイン、クライアントID、そしてローカル開発用のコールバックURLなどを設定します。これらの設定値は、環境変数経由で管理するのがベストプラクティスです。
  • バックエンドAPIのローカルテスト: ローカルでバックエンドAPIを開発・テストする場合、クライアントがAPIにリクエストするアクセストークンの audience クレームが、Auth0に登録したAPIのIdentifierと一致している必要があります。バックエンドAPI側のJWT検証ライブラリも、この audience を検証するように設定します。

これらの設定を怠ると、「Callback URL mismatch」やCORSエラーなど、ローカル開発中によく遭遇する問題が発生し、開発の妨げとなります。開発初期段階でこれらのURLを正確に設定することが、スムーズな開発体験の鍵です。

デバッグテクニックとトラブルシューティング

Auth0関連の問題が発生した場合、適切なデバッグトラブルシューティングが重要です。

  • Auth0テナントログの活用: Auth0ダッシュボードまたはManagement API経由でアクセスできるテナントログは、認証フローの各ステップ、Actionsの実行状況、エラー発生時の詳細情報などを確認するための最も重要な情報源です。エラーコードやエラーメッセージから問題の原因を特定する手がかりが得られます。
  • Actionsのデバッグ: Actionsスクリプト内では、 console.log() を使用して変数や処理の途中経過を出力できます。これらのログは、Auth0ダッシュボードの「Monitoring > Logs」セクションや、Real-time Webtask Logs拡張機能で確認できます。デバッグ用のログ出力を、設定値(例: event.secrets.DEBUG_MODE === 'true' )に基づいて条件付きで有効にすると便利です。
  • HAR (HTTP Archive) ファイルの取得: 複雑なリダイレクトフローやトークン交換時の問題を診断する際には、ブラウザの開発者ツールを使用してHARファイルをキャプチャし、リクエストとレスポンスの詳細な流れを分析することが有効です。
  • Auth0 Support Centerのツール: Auth0 Support Centerでは、テナント設定の健全性をチェックする「Run Production Check」ツールなどが提供されており、一般的な設定ミスを発見するのに役立ちます。
  • 一般的な問題と解決策: レート制限超過 、コールバックURLや許可オリジンの設定ミス、カスタムドメイン関連の問題、メールテンプレートのカスタマイズ不備、トークン検証エラーなどがよくある問題です。公式ドキュメントやコミュニティフォーラムで同様の事象が報告されていないか確認することも有効です。

Auth0 Deploy CLIやTerraformによるCI/CD

複数のAuth0テナント(開発、ステージング、本番など)間で設定を同期・管理する場合、手動での作業はエラーが発生しやすく非効率です。Auth0の設定をコードとして管理(Infrastructure as Code)するために、いくつかのツールが利用できます。

  • Auth0 Deploy CLI: Auth0が公式に提供するツールで、テナント設定をYAMLまたはJSON形式のファイルとしてエクスポート・インポートできます。環境固有の値を動的に置き換えるキーワード機能も備えています。
  • Terraform (Auth0 Provider): Terraformは汎用的なInfrastructure as Codeツールですが、公式のAuth0プロバイダを利用することで、Auth0リソース(アプリケーション、API、Actionsなど)をHCL(HashiCorp Configuration Language)で宣言的に管理できます。

弊社では、これらの選択肢の中からTerraformを採用しました。決め手となったのは、Terraformが持つplan (dry-run) 機能です。 これにより、実際の設定変更を適用する前に、どのような変更が行われるかを詳細に確認でき、意図しない変更を防ぐことができます。

Auth0 Deploy CLIにもインポート時に変更差分を表示する機能はありますが、Terraformのplanはより広範なIaCプラクティスと親和性が高く、安全な運用体制の構築に貢献すると判断しました。

これらのツールをCI/CDパイプラインに組み込むことで、設定変更のテストとデプロイを自動化し、一貫性と信頼性を高めることができます。これにより、Auth0の設定管理を「Infrastructure as Code」の原則に近づけることができ、運用成熟度の向上に繋がります。

ログ収集とモニタリング

Auth0の運用において、ログの収集とモニタリングは、システムの健全性の維持、セキュリティインシデントの検知、そして利用状況の分析のために必要です。

  • Auth0テナントログ: 前述の通り、認証成功・失敗、管理者操作、APIコール、エラーイベントなど、詳細なログが記録されます。
  • ログストリーミング: Auth0のログストリーミング機能を利用すると、これらのテナントログをリアルタイムで外部のログ管理・分析システム(例: Splunk, Datadog, AWS EventBridge, Azure Event Gridなど)にエクスポートできます。これにより、より高度な分析、アラート設定、長期的なログ保存が可能になります。プロジェクトの初期段階からログストリーミングを設定し、監視すべき重要なイベント(例: 多数のログイン失敗、MFA設定の変更、管理者権限の操作、レート制限エラーなど)を定義しておくことが、プロアクティブな問題解決とセキュリティ監視の鍵となります。
  • Auth0ステータスの監視: Auth0自体のサービス稼働状況は、 status.auth0.com で確認できます。重要な通知を受け取るために、このステータスページの更新情報を購読しておくことが推奨されます。

これらの開発・運用上のヒントを実践することで、Auth0導入プロジェクトの効率性、安全性、そして信頼性を高めることができます。

まとめ

本記事では、Auth0導入を検討・推進するエンジニアの方々に向けて、コアコンセプトの理解から環境構築、認証フローの実装、Actionsによる拡張、ユーザー管理、セキュリティ強化、そして開発・運用のヒントに至るまで、技術的な側面を解説してきました。

Auth0は、その柔軟性、開発者中心の設計思想、そして豊富な機能群により、認証・認可の課題を解決できるIDaaSです。しかし、そのポテンシャルを引き出すためには、以下の点が重要となります。

  • コアコンセプトの正確な理解: テナント、アプリケーション、API、コネクション、そしてActionsといった基本要素の役割と相互関係を把握することが設計の第一歩です。
  • 適切な認証フローの選択とセキュアなトークン管理: アプリケーションの特性に合わせた認証フローを選び、特にSPAにおいてはトークンの保存方法や更新戦略(サイレント認証、リフレッシュトークンローテーション)に注意を払う必要があります。
  • Actionsによる積極的なカスタマイズ: Actionsを活用することで、カスタムクレームの追加、動的なMFA制御、リスクベース認証といった要件に対応できます。
  • セキュリティベストプラクティスの遵守: MFAの導入、バックエンドでのトークン検証、Attack Protection機能の活用は、セキュリティを確保する上で重要です。
  • 計画的な導入と運用体制の確立: 開発・ステージング・本番環境の分離、ローカル開発環境の整備、Deploy CLIやTerraformを用いたCI/CDの導入、そしてログ収集とモニタリング体制の構築は、プロジェクトの品質と安定運用を支えます。

Auth0の導入と運用は、一度設定して終わりというものではなく、アプリケーションの成長やセキュリティ脅威の変化、Auth0自体の機能進化に合わせて継続的に改善していく事が必要です。

本記事が、読者の皆様が直面するであろう課題を乗り越え、Auth0を活用するための一助となれば幸いです。正確な情報はAuth0の公式ドキュメントやコミュニティフォーラムなどで確認してください。

最後に

株式会社ACESでは、「アルゴリズムで、社会はもっとシンプルになる」というビジョンを掲げ、テクノロジーで社会課題の解決を目指す仲間を積極的に募集しています。

本記事で紹介したようなAuth0導入の裏話や、Terraformを用いたベストプラクティスに基づいたAuth0の管理方法など、さらに深い技術的なディスカッションに興味がある方は、ぜひ一度お話を聞きに来てください。

acesinc.co.jp

「反響は二の次」で始めた、Tech Blog継続の舞台裏

こんにちは、株式会社ACES でテックリードをしている奥田(@masaya_okuda)です。

私の所属するAIソフトウェア事業部の開発チームはエンジニア7名ほどの1チームなのですが、昨年12月よりテックブログ強化月間をスタートし、本記事が19記事目となります!

多い時は毎週1記事を更新する月もあり、なかなかの更新頻度だと思っています!(上には上がたくさんいますが…😅)

一方でどの開発チームでも、テックブログをもっと運用しようと思った際に一度は、

  • 執筆の負担が大きい(他の作業もある)
  • 執筆ネタが思いつかない
  • そもそも何目的で書くんだっけ?

と、なかなか前に進めないことがあると思います。

本記事では私たちの開発チームが何を目的に、どんな進め方で更新したか?やってみてどうだったか?をご紹介します。

特に、チームリードされているエンジニアの方の参考になれば幸いです。

開発チームの前提と課題

私の所属する開発チームはAI議事録ツール「ACES Meet」を開発しています。ですが会社としてはAIに関する受託開発事業が先行しており、BtoB SaaSの自社サービスを運営する私の事業部の認知度は高くありませんでした。そこでもっと採用強化に繋げるためには?とHowを考えていました。

エンジニアイベントの登壇は機会が限られるため、もっとライトな手段としてテックブログの定期的な更新が候補に上がったのですが、最初はあまり乗り気ではありませんでした。

入社時に1本書いてみた際に非常に時間がかかったため、「本当に継続していけるのか?」と同僚のテックリードに不安をこぼしたことを覚えています。

転機、反響がなくても良いことに気づく

テックブログの運営を考えるにあたり、非常に影響を受けた他社事例をご紹介します。

KINTOテクノロジーズ株式会社

blog.kinto-technologies.com

KINTOテクノロジーズ株式会社の上記テックブログは、「反響のある記事を頑張ってかかないと」と思っていた自分には目から鱗でした。この記事の中では、「会社で自分たちがやったことが例え目新しくなくても、会社の外の人には文章で残さないと伝わらない」ことを述べています。

開発チームで強化月間を始める際にも、

  • 大きな反響を狙うことはしない
  • 特に採用課程で興味を持ってもらった候補者様に、自己紹介するつもりで書こう

と決めました。

ファインディ株式会社

tech.findy.co.jp

Findy社は特に開発生産性の高い組織としてエンジニア界隈で認知をとっている印象で、思わず頷いてしまう素晴らしい記事や発表資料を多く公開しています。

一方で、各記事よく読むと内容が似た記事もたくさんあります。ではそれを被っていると感じるかといえばそうではなくて、「開発生産性を高めるという文化が会社全体に浸透している」と私は感じました。

私はこれを「テックブログを面で捉えている」のだと思っています。開発チームが本当に大切にしている文化は、言葉を変えて何度でも執筆して良いのです。

テックブログの更新戦略

テックリードの福澤とブログを定期更新する戦略を考えるにあたり、初期構想は以下のような内容でした。

  • 私たちが候補者に伝えたい開発文化や目指していることを優先し、反響は二の次
  • まずは「ユーザーへの価値提供と技術品質の高さの両方に妥協せず取り組む文化」を伝えたい
  • 伝えたいことを網羅的に書いた「親記事」をまずは執筆し、次にその「詳細記事」を書こう

特に、

  • 伝えたいことを網羅的に書いた「親記事」をまずは執筆し、次にその「詳細記事」を書こう

は振り返ると非常に良い進め方だったと思います。

設計からリリースまでのプロセスを紹介した記事をまずは執筆し、その詳細なステップをご紹介することでスムーズに執筆できました。

tech.acesinc.co.jp

tech.acesinc.co.jp

継続することで得た認知、チームへの影響

強化月間はペースを落としつつもまだ継続できており、本記事が19記事目になります。まず継続した成果として、「テックブログをたくさん更新している会社」として勉強会等で認知を実感することができました!

また、たくさん記事を書くとそのうちの何本かは反響をいただくこともできました!

tech.acesinc.co.jp

tech.acesinc.co.jp

tech.acesinc.co.jp

当初の目的でもあった「候補者に私たちの開発文化や大切にしていることを伝える」に関しても、採用面談の最後に候補者の関心に合わせて記事を共有できるようになりました!

AIによる記事執筆のサポート

特に今は生成AIの登場によって、「そもそも記事を人間が執筆するのか?」は私も常々考えます。私は文章を書く際によく手が止まってしまうため、今はChatGPTの音声入力を利用して以下の手順で書くことが多いです。

  1. 記事にしたい内容を、音声入力で大雑把に話してChatGPTに章構成を考えてもらう
  2. 章構成がFixしたらChatGPTに共有する
  3. 章ごとに音声入力で話してChatGPTに執筆してもらう
  4. 最後に文章を調整
  5. 完成した文章をブログタイトル生成専用のMy GPTに共有してタイトルを決める

上記の手順で、大体1時間〜2時間ほどで記事を執筆できるようになりました。ここはより効率化したいのですが、「もっとAI活用できるぞ!」という開発チームの事例をお待ちしています🙇!

まとめ

ここまで、1つの開発チームで、半年間テックブログを更新し続けた取り組みについてご紹介しました!個人ではなく企業としてテックブログを運営する際は、

  • 記事を書く目的をチームで合意する
  • 重要としないことをチームで合意する
  • 滑り出しの数記事は戦略を考える

ということを意識すると、チームメンバーを巻き込んで推進しやすいかと思います。

また記事の中でご紹介しましたが、私たちは特に設計時のタスク分解や仮実装に重きをおいて、「ユーザーへの価値提供と技術品質の高さの両方に妥協せず取り組む文化」を大切にしています。他の記事もご覧いただけると幸いです!

本記事を通じてACES Meetの開発チームにご興味をお持ちいただけましたら、ぜひカジュアル面談でお話ししましょう!

youtrust.jp

youtrust.jp