🔐

Best Practices for B2B SaaS Architecture with Auth0

2024/12/07に公開

はじめに

ログラスに転職して3年が経ち、ついに4年目に突入してしまいました。
ログラスで書くアドベントカレンダーはこれで3回目になると思うと、何を書くか迷ってしまいますね...。

ということで、今回は過去に書いていたAuth0 Organizationの記事の発展版を書いてみようと思います。
https://zenn.dev/urmot/articles/8c18d8b49d822c

今回の記事ではAuth0の「Multiple Organization Architecture」から、B2B SaaSを提供するプロダクトの認証部分をAuth0を使って実現するベストプラクティスについて学んだ内容をまとめようと思います。

上記のドキュメントはB2B SaaSでAuth0を利用している企業のエンジニアであれば、一度は読んでおいても損はないほどしっかりと書かれているので、一読することをオススメします。

Auth0におけるマルチテナンシーの設計

B2B SaaSを作るためには、顧客である企業が自社サービスを利用する際にどのレベルでテナントを分離するか設計する必要があります。

データベース一つとっても、顧客ごとのDBインスタンスを作成したり、顧客ごとにdatabaseを論理的に分離するなど様々な方法が考えられると思います。

では、Auth0ではどうするべきでしょうか?

もちろん、サービスの性質や利用する顧客の性質にもよるので一概には決まらないと思いますが、この記事ではB2Bのアーキテクチャシナリオで語られている一般的なユースケースにおけるベストプラクティスについて説明していきます。

Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
Multiple Organization Architecture

このドキュメントではサンプルアプリケーションを使って説明されているので、まず題材となるアプリケーションを説明します。

Travel0というオンライン旅行代理店サービスを提供する架空の会社が提供しているSaaSアプリケーションを考えます。

Travel0 出張予約

  • サービス詳細
    • 従業員がログインして出張を予約できるアプリケーション
    • Travel0のカスタマーサクセスが各テナントにログインしてサポートすることがある
  • 利用する顧客
    • 毛利探偵事務所: 小さな探偵事務所。IT部門がなくIdPもない。
    • 妃法律事務所: 大規模な法律事務所。IT部門はあるがIdPは利用していない。
    • 阿笠研究所: 小規模な研究所。AzureADで研究員を管理している。

ユーザーの分離

まず最初に検討すべきはユーザーの分離度です。
テナント間でユーザーを共有することがあるのか?その場合同じ認証情報を使いたいのか?などを検討する必要があります。

例えば、毛利探偵事務所のユーザーが妃法律事務所のユーザーとしてログインしたいとなることはないので、この場合は毛利探偵事務所と妃法律事務所のユーザーはテナント毎に独立したユーザーになります。
以下の図のようなイメージです (図はAuth0のドキュメントのものです)


https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture#users-isolated-by-organization

逆に、Travel0サポートのユーザーは毛利探偵事務所にも妃法律事務所に対してもサポートする必要があるため、どちらのテナントにもログインできる必要があります。
このとき一人のユーザーが毛利探偵事務所と妃法律事務所に別々にユーザーを作成するように設計するのであれば、テナント毎に独立したユーザーとすることができます。
1ユーザーで毛利探偵事務所と妃法律事務所にログインする場合はテナント間で共有されるユーザーとなります。
以下の図のようなイメージです (図はAuth0のドキュメントのものです)


https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture#users-shared-between-organizations

Auth0におけるマルチテナンシーの実装

Auth0でこのようなテナント毎に独立したユーザーやテナント間で共有されるユーザーを表現するにはどのようにすれば良いでしょうか?
それぞれのケースで実現方法を考えてみます。

テナント毎に独立したユーザー

テナント毎に独立したユーザーを作成する方法についてはこちらのドキュメントにまとまっています。

https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning#organizations

まず、利用する顧客毎にAuth0 Organizationを作成します。
Organizationには利用するAuth0接続をAuth0 Organization毎に設定できるため、顧客が利用する接続方法に合わせてAuth0 Organizationをカスタマイズできます。

では、テナント毎に独立したユーザーを考えるときには、Auth0 Organizationをどのように設定すれば良いでしょうか?
これも先ほどの具体例をベースに考えてみます。

以下のように設計して独立したユーザーを実現してみましょう。

  • 毛利探偵事務所と妃法律事務所ではIdPを持たないためAuth0のデータベース接続を利用する
  • 阿笠研究所所ではAzureがあるのでAzure経由でログインする
  • Travelサポートのユーザーはテナント毎に別々のユーザーを作成する。

Auth0 Organizationの設定はそれぞれ以下のようになります。

  • Mori Organization
    • display_name: 毛利探偵事務所
    • connection:
      • Mori Auth0 Database接続
  • Kisaki Organization
    • display_name: 妃法律事務所
    • connection:
      • Kisaki Auth0 Database接続
  • Agasa Organization
    • display_name: 阿笠研究所
    • connection:
      • Agasa AzureAD Enterprise接続

ここで特殊な点としてはOrganization別にAuth0 Databaseを分割して追加している点です。

Add a new a database connection for that Organization (if you have isolated users per organization)
https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/provisioning#provisioning-organizations

テナント毎に独立したユーザーを実現するには新しいデータベース接続を作成するようにとあります。
この場合は接続レベルでユーザーが分離される形になります。

このようにする意図としては以下の様になります

(自動翻訳済み) 組織に分離: すべてのユーザーは 1 つの組織にのみ所属します。ユーザーが複数の組織に所属することは意味がありません。また、たとえ所属していたとしても、 別の組織用に別の「ID」を持つのが妥当です。 たとえば、2 つの異なる店舗でパートタイムで働いている小売店の従業員は、両方の店舗で SaaS アプリケーションを使用していても、それぞれの店舗に 2 つの異なるログイン情報を持っています。
https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/provisioning#provisioning-organization-users

個人的にはデータベース接続をOrganizationレベルで分けるという発想がなかったので驚いた点でした。
完全にテナント間でユーザーを分離するのであれば、同じユーザーだとしても異なるIDをもたせるべきという思想に基づいているようです。

テナント間で共有されるユーザー

次に、テナント間で共有されるユーザーを実現してみましょう。
ここではTravel0サポートのユーザーが共通されるユーザーになります。

これを踏まえた上でOrganizationの設定を考えてみます。

  • Mori Organization
    • display_name: 毛利探偵事務所
    • connection:
      • Mori Auth0 Database接続
      • Travel0 Auth0 Database接続
  • Kisaki Organization
    • display_name: 妃法律事務所
    • connection:
      • Kisaki Auth0 Database接続
      • Travel0 Auth0 Database接続
  • Agasa Organization
    • display_name: 阿笠研究所
    • connection:
      • Agasa AzureAD Enterprise接続
      • Travel0 Auth0 Database接続

Enable the existing shared database connection for that Organization (if you are sharing users)
https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/provisioning#provisioning-organizations

テナント間で共通するユーザーの場合は、データベースコネクションを追加するように書いています。
しかし、この場合は注意が必要です。

(自動翻訳済み) Auth0では、規定複数データベースとカスタムデータベース接続Auth0組織にこれらのタイプの接続を複数関連付けることはお勧めしません。
https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/provisioning#provisioning-organization-users

1つのAuth0 Organizationに複数のデータベース接続を追加することは推奨されていません。
この場合はログイン時にどのデータベース接続を利用するのか選択する必要があると思います。

また、後述する自動サインアップが利用できなくなるため本当に必要なケース以外は避けるべきでしょう。

Travel0サポートのように複数のテナントに追加される接続がある場合には、Enterprise接続を利用するなどの回避方法を実施するなどが考えられます

  • Mori Organization
    • display_name: 毛利探偵事務所
    • connection:
      • Mori Auth0 Database接続
      • Travel0 Okta Enterprise接続
  • Kisaki Organization
    • display_name: 妃法律事務所
    • connection:
      • Kisaki Auth0 Database接続
      • Travel0 Okta Enterprise接続
  • Agasa Organization
    • display_name: 阿笠研究所
    • connection:
      • Agasa AzureAD Enterprise接続
      • Travel0 Okta Enterprise接続

Auth0 Organizationでのサインアップ

Auth0 Organizationを利用している場合に、テナントにユーザーを作成するにはどうするのが良いでしょうか?
これについてもドキュメントに詳しくまとまっています。
https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning#invitation

Auth0 Organizationには招待機能がついています。
この招待機能を使うことで、ユーザーをOrganizationに追加するフローを簡略化することができます。


https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning#database-connection

招待機能を使ったユーザー招待フローは以下の様になります。

  1. アプリケーションでユーザーを追加
  2. アプリケーションは招待リンクを発行し、メールを送信
  3. ユーザーはメールリンクから、サインアップ画面に遷移
  4. サインアップ画面でサインアップする
    • データベース接続であれば、パスワードを入力してサインアップ
    • Enterprise接続であれば、IdPのログイン画面に遷移しログインする
    • Travel0サポートのように既に別のテナントに存在するユーザーであれば、ログイン画面に遷移し、ログインする
  5. サインアップするとAuth0上にユーザーが作成され、自動的にAuth0 Organizationに追加される
  6. コールバックURLにリダイレクトされる
  7. ユーザーの初期化処理などを行う

Auth0 Organizationの招待機能の良いところはユーザーの招待フローがデータベース接続であろうがEnterprise接続であろうが、既に存在するユーザーであろうが同じフローにすることができる点です。
特にデータベース接続では招待を受けたユーザーだけがサインアップ可能にするフローが組めるので、アプリケーション側で管理APIを実行してユーザー作成をする必要がありません。
Auth0 Organization画面で以下の設定にする必要があります。

  • Membership On Authentication: Enable Auto-Membership
  • Organization Signup:Enable Signup

このときにOrganizationに複数のデータベース接続が紐づいているとこの自動サインアップがうまく動作しないので、注意が必要です。

まとめ

Auth0でB2B SaaSのマルチテナンシーを実現する方法をベストプラクティスのドキュメントをもとに解説してみました。
この記事ではユーザーのサインアップまでしか扱えませんでしたが、ドキュメントではもっと細部まで深く書かれております。

B2B以外にもB2CB2E(Bessiness To Employee)のユースケースまで書かれているので、読み応えのあるドキュメントになっています。

Auth0は正しく使わないとシステムを複雑にしてしまうのですが、ベストプラクティスに沿った使い方をすると認証を司る強力なツールとして利用できると思っています。
これからもAuth0を上手く使う術は探っていこうと思います!

また、冒頭書く内容に迷った的なことを書いたのですが、実はシリーズ2にも参加します!
何を書くかはこれから頑張って考えようと思います。

少しでもご興味を持った方や、詳しく話を聞いてみたいと思った方はPittaで面談公開しておりますので、どんな話題でも面談組んで頂けますと嬉しいです😄

https://pitta.me/matches/VJBJkQvRYmin

株式会社ログラス テックブログ

Discussion