こんにちは、新規事業開発室の加藤です。私たちのチームでは新規事業のプロダクトとしてB2BのマルチテナントSaaSを開発しており、その認証にAuth0を使っています。今回Auth0を初めて使用する中で試行錯誤することが多かったので、最初から知っておきたかったことをまとめておきます。
Auth0とは
Auth0はIdentity as a Service (IDaaS) と呼ばれる認証をサービスとして提供するSaaSです。シンプルなID・パスワードによるログインや、Google・Facebookアカウントなどのいわゆるソーシャルログインだけでなく、エンタープライズ向けのG SuiteやAzure AD、SAMLなどのシングルサインオン (SSO) に幅広く対応しているのが特徴です。
なお、Auth0は自社の従業員のID管理にも利用できますが、本稿ではあくまでプロダクト開発者目線で、プロダクトのエンドユーザーの認証を目的として利用しています。また、エンタープライズ向けのSSOに対応しているDeveloper Pro以上のプランを前提としています。
Auth0の用語
本稿を読み進める前提として、Auth0の用語について解説しておきます*1。一般的な単語が使われているので、区別しやすいよう、本稿ではなるべくAuth0をつけて表記します。
- Auth0テナント
- Auth0における論理的な分離単位
- 名前が重複しなければ自由に作成できる
- 課金はこのAuth0テナントに紐付く(Developer/Developer Proプランの場合。Enterpriseプランでは企業ごとの課金)
- Auth0テナントの管理者は複数設定できる
- Auth0ドメイン
- Auth0のAPIやログイン画面で使用されるドメイン名
- USリージョンでは
<テナント名>.auth0.com
のような形式 - Auth0テナントと1対1に対応する
- ログイン画面などエンドユーザー向けの機能ではカスタムドメインも使える
- Auth0アプリケーション
- エンドユーザーの認証結果を使用するOAuth 2.0のクライアントを表し、次の4種類に分かれる
- Native: ネイティブアプリ
- Single Page Web Applications: Reactなどのシングルページアプリケーション
- Regular Web Applications: 一般的なWebアプリケーション
- Machine to Machine Applications: バッチ処理など
- 1つのAuth0テナントに複数作成できる
- Auth0アプリケーションごとにClient ID/Secretのペアが発行される
- エンドユーザーの認証結果を使用するOAuth 2.0のクライアントを表し、次の4種類に分かれる
- Auth0コネクション
- 実際にエンドユーザーの認証を行う手段を表し、次の4種類に分かれる
- Database: ID・パスワードによるログイン
- Social: ソーシャルログイン
- Enterprise: エンタープライズ向けのシングルサインオン
- Passwordless: SMSまたはEmailによるログイン
- 1つのAuth0テナントに複数作成できる
- 実際にエンドユーザーの認証を行う手段を表し、次の4種類に分かれる
Auth0アプリケーションとAuth0コネクションは1つのAuth0テナントにそれぞれ複数作成できますが、その組み合わせのうちどれを有効にするか、柔軟に設定できます。
Auth0でのB2BマルチテナントSaaSの認証
Auth0をマルチテナントSaaSで使うには、以下の記事が非常に参考になるので、目を通しておくことをオススメします。
この記事では大きく2種類のシナリオが解説されています。
- B2B SaaS Multi-Tenant Application
- プロダクトの全テナントを単一のAuth0アプリケーションで管理する
- B2B SaaS Single Tenant
- プロダクトのテナントごとに1つのAuth0アプリケーションを作成する
記事内でもそれぞれのシナリオの採用方針が記載されていますが、プロダクトにおいてユーザーがテナントを跨がないことが確実な場合は、後者を採用する方がテナント間の分離度が高くて安心です。しかし、後者を採用する上で考慮すべき点があります。
- 後者のシナリオでは、プロダクトのテナントごとのClient ID/Secretをデータベースなどに保存することになると思いますが、OAuthの認証を行うライブラリ*2では、Client ID/Secretが動的に増えることを想定してない場合があります。その場合、通常とは異なる使い方をしたり、ライブラリに手を入れたりする必要があります。
- 後者のシナリオで使い始めた後に前者のシナリオに切り替えたいと思った場合、Enterpriseコネクションについてはアプリケーションとの組み合わせを見直せば良いですが、Databaseコネクションについては複数のDBを1つにまとめるのは簡単ではありません(逆も然りですが)。
私たちのプロダクトは新規事業で、今後どうなるかは誰にもわかりませんが、実装コストの低さとテナントを跨ぐ可能性を残しておいた方が良いという判断から、前者のシナリオに近い構成を取りました。
以降ではこの構成を前提とし、Auth0を使う時に知っておいた方がよかったことをまとめておきます。
1. 課金はAuth0テナント単位(Developer/Developer Proプランの場合)
上述のように、Auth0ではテナントを自由に作ることができますが、Developer/Developer Proプランではテナントに課金が紐付きます。私たちは最初に作られるランダムな名前のテナントに年払いのSubscriptionを設定してしまったため、ちょっと残念なことになってしまいました。テナント名は後から変更できないので、注意しましょう。
なお、上記参考記事の最後で「Not covered in this Article」として、プロダクトのテナントごとにAuth0のテナントを分けるシナリオにも触れられていますが、これはEnterpriseプラン前提のシナリオだと言えるでしょう。
2. メール文面のカスタマイズにはカスタムメールプロバイダーが必要
Auth0の管理画面でユーザーを作成したときやエンドユーザーがログイン画面からパスワードリセットしたときには、Auth0からエンドユーザーにメールが送られます。これらのメール文面をカスタマイズするには、Amazon SESやSendGridなどのカスタムメールプロバイダーを設定する必要があります。デフォルトのメールプロバイダーは検証用途のものとされており、本番運用するにはほぼ必須の設定と言えます。予め考慮しておくとよいでしょう。
なお、テスト用のAuth0テナントでは、カスタムメールプロバイダーにMailtrap のSMTPサーバーを設定することで、テスト時に不要なメールが送られないように設定しています。
3. 単一のAuth0アプリケーションを使う場合、新ログイン画面は向いてない
Auth0でホストされるログイン画面 (Universal Login) はClassicとNewの2種類から選択できます。
デフォルトはClassicですが、新しいNewを選択したくなります。しかし、NewはJavaScriptを使用しないログイン画面なので、単一のAuth0アプリケーションに複数のEnterpriseコネクションが紐づいている場合、ログイン画面にそれらのコネクションを使うためのボタンが全て表示されてしまいます。
この場合、おとなしくClassicを使うしかなさそうです。ClassicではHome Realm Discovery (HRD) と呼ばれる、エンドユーザーが入力したメールアドレスのドメインに応じて適切なEnterpriseコネクションのログイン画面に遷移させる機能が使えます。
4. Enterpriseコネクションの認証結果のメールアドレスを無条件で信用しない
HRDを使うと、エンドユーザーが入力したメールアドレスのドメインに応じて適切なログイン画面に遷移しますが、そこで認証されたユーザーのメールアドレスが同じドメインを持つとは限りません。
例えばメールアドレスのドメインが evil.example.com
として登録されているEnterpriseコネクションがあり、そこで認証されたユーザーのメールアドレスが [email protected]
としてAuth0に返ってきた場合、これを信用すると成り済ましが起きてしまいます。
これを防ぐにはAuth0のルールが使えます。ルールはエンドユーザーが認証した時に実行できるJavaScriptのコードです。Auth0の管理画面からルールを作成しようとすると、テンプレートとなるルールが数多く表示されます。その中から Check If User Email Domain Matches Configured Domain というルールを選択して有効にすると、メールアドレスのドメインが、Enterpriseコネクションに登録されたドメインと一致する場合のみ認証に成功します。
5. エンドユーザーが入力したメールアドレスを無条件で信用しない
Auth0に限った話ではありませんが、Databaseコネクションを使う場合、エンドユーザーがサインアップ時に入力したメールアドレスが本人のものである保証はありません。プロダクト側でメールアドレスを検証する処理を行っていない場合、エンドユーザーの利便性はやや落ちますが、メールアドレスの有効性を確認するまでログインできないようにできます。これもルールの追加で実現でき、ルール作成時のテンプレートから Force email verification を選択します。
なお、私たちのプロダクトでは以下のページの方法を参考にし、プロダクトでのユーザー作成時にパスワードリセットメールを送り、それをメールアドレス確認メールと兼ねる形にしました。
Auth0 setting to force password reset after first login? - #11 by kentaro_ueda - Auth0 Community
6. Azure ADでエンドユーザーのメールアドレスを取得するには一工夫必要
EnterpriseコネクションでAzure ADを使用した場合、デフォルトの設定ではログインしたエンドユーザーのメールアドレスを取得できませんでした。コネクションの設定でExtended Profileを有効にすると user.upn
フィールドでメールアドレスが取得できるので、これを user.email
フィールドに代入するルールを作って対応しました。Auth0側でこのような差異を吸収してくれると嬉しいのですが。
function (user, context, callback) { console.log('===> Rule started: Fill user email for Azure AD users'); console.log(`user.email: ${user.email}`); console.log(`user.upn: ${user.upn}`); // Azure ADではemailがなく、Extended Profileを有効にした場合にupnがあるので、upnをemailに入れる。 user.email = user.email || user.upn; return callback(null, user, context); }
まとめ
新しいサービスを使い始めるときは学ぶことが多くあり、どうしても時間がかかってしまいます。ただ「認証」という、重要ではあるもののビジネスのコアでない領域にSaaSを活用することで、プロダクト開発にかかる時間を短縮できることには大きな意義があるので、今後もAuth0とは上手にお付き合いしていければと思います。
本稿がAuth0を活用してマルチテナントSaaSを開発する方のお役に立てば幸いです。
buildersbox.corp-sansan.com
buildersbox.corp-sansan.com
buildersbox.corp-sansan.com
*1:Auth0の基本構成を図で理解する #Auth0JP | Developers.IO にもわかりやすく解説されています。
*2:例えばNode.jsのPassportやPythonのPython Social Auth など