---
title: "Blazor B2B SaaSアプリケーションでセルフサブスクリプションモデルを有効にする方法"
description: "Auth0.NET SDKを使用してB2B SaaSアプリケーションでセルフサブスクリプションを有効にし、Organizationの作成プロセスを自動化する方法を学びます。"
authors:
  - name: "Andrea Chiarelli"
    url: "https://auth0.com/blog/authors/andrea-chiarelli/"
date: "Jun 2, 2025"
category: "Developers,Tutorial,.NET"
tags: ["dotnet", "blazor", "organizations", "multitenancy", "management-api"]
url: "https://auth0.com/blog/jp-enable-self-subscription-in-blazor-b2b-saas-application/"
---

# Blazor B2B SaaSアプリケーションでセルフサブスクリプションモデルを有効にする方法

> 本記事は 2025年3月25日に更新された「[Enable Self-Subscribing Model in Your Blazor B2B SaaS Application](https://auth0.com/blog/enable-self-subscription-in-blazor-b2b-saas-application/)」を機械翻訳した記事です。

[最近の記事](https://auth0.com/blog/jp-auth0-organizations-for-b2b-saas-blazor-web-apps/)では、Auth0 OrganizationsがB2B Blazor Webアプリケーションの構築にどのように役立つかを探りました。Auth0ダッシュボードを使用して顧客向けのOrganizationを作成および構成する方法を学びましたが、これは簡単であるものの、手動での介入が必要であり長期的には持続可能な方法ではありません。この記事では手動での作業を回避し、Auth0 Management APIを介してOrganizationの作成と構成を自動化する方法を学びます。この手法を用いると、B2B SaaSアプリケーションとしての成功がさらに促進されます。


## Organizationの作成を自動化する理由


Auth0ダッシュボードを使用してB2B顧客向けのOrganizationを作成するのは非常に簡単ですが、いくつかの理由からスケーラブルではありません。


- 新しいB2B顧客ごとに手動の作業が必要です。時間がかかるだけでなく、エラーが発生しやすくなります。
- ビジネスが成長し、幸いにも多くの新しい顧客を獲得した場合、この作業は膨大になり、ボトルネックになるリスクがあります。新しい顧客が製品を試すためにOrganizationの構築を待っていることを想像してみてください。この状況は製品を紹介する最良の状態ではありません。
- 現代のビジネスシナリオでは、顧客はセルフサービスを好みます。たとえば、SaaSアプリケーションの無料トライアルに登録し、必要に応じて連絡を取りながら、自律的に製品を評価することを好みます。
- 顧客に対してセルフサービスでOrganizationの作成機能を提供することで、ビジネスの成功につながる[Product-Led Growth (PLG)](https://www.emergeagency.com/insights/detail/product-led-growth-plg-ultimate-guide/)の原則に沿うことができます。


それでは新しい顧客がB2B SaaSアプリケーションへのサブスクライブとOrganizationの作成をセルフサービスで開始できる機能を実装する方法を見ていきましょう。


## Organization自動作成のシナリオ


SaaSとして公開されているB2B Blazorアプリケーションがあり、新しい顧客が自律的にサブスクライブして使用を開始できる機能を追加したいとします。たとえば、期間限定でSaaSアプリケーションを無料で使用できるようにしたり、機能の一部を永久に無料で使用できるようにしたりできます。


顧客が製品を評価するためにどのようなアプローチを取りたいかにかかわらず、アプリにサブスクライブすると、新しいAuth0 Organizationが作成され、そのアカウントがそのOrganizationに追加されます。


このシナリオでは、アプリケーションはAuth0との関連で2つの役割を果たします。


- **アプリケーションの役割**: これはBlazorアプリケーションの通常の動作、つまり、アプリケーションが顧客のユーザーに機能を提供する役割です。この役割では、ユーザーがAuth0 Organizationに属するものとして認証されます。
- **オンボーディングの役割**: これは、新しい顧客のサブスクリプションプロセス中にアプリケーションが果たす役割です。この段階では、新しいユーザー向けのOrganizationはまだ存在せず、Organizationのコンテキスト外で作成および認証されます。この役割では、アプリケーションは[Auth0 Management API](https://auth0.com/docs/ja-jp/api/management/v2)を使用して新しいOrganizationを作成し、最終的に新しいユーザーをメンバーとして追加します。


アプリケーションの役割を果たすには、[Regular Webアプリケーションとして登録](https://auth0.com/docs/ja-jp/get-started/auth0-overview/create-applications/regular-web-apps)し、[Organizationsを使用するように構成](https://auth0.com/docs/ja-jp/manage-users/organizations/login-flows-for-organizations#organization%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E6%A7%8B%E6%88%90%E3%81%99%E3%82%8B)する必要があります。


オンボーディングの役割を果たすには、Auth0ダッシュボードで新しいアプリケーションを登録し、Blazorアプリケーションにいくつかの変更を加える必要があります。これについては後で説明します。


この記事で説明する手順を開始するには、次のコマンドを使用してサンプルBlazorアプリケーションをダウンロードできます。

```shell
git clone --branch organization-manual --single-branch https://github.com/andychiare/MyBlazorSaaS
```

アプリケーションを登録および構成するには、添付のREADMEファイルの指示に従ってください。


以下のセクションでは、次のことを行います。

 - アプリケーションのオンボーディングの役割を有効にする。
 - 顧客のサブスクリプションプロセスを開始する。
 - 新しいサブスクライバー顧客に代わってAuth0 Organizationを作成する。


<include src="ebook-ads/dotnetIdentity" />

## オンボーディングプロセスを有効にする


アプリケーションのオンボーディングの役割を有効にするには、Auth0テナントに新しいアプリケーションを登録します。その後、オンボーディングプロセスを構成するため、コードにいくつかの変更を加え、Auth0 Management APIとの対話を有効にします。


### オンボーディング用にアプリケーションを登録する


まず、[Auth0 ダッシュボード](https://manage.auth0.com/)にアクセスし、次の図に示すように[Regular Webアプリケーションを登録](https://auth0.com/docs/ja-jp/get-started/auth0-overview/create-applications/regular-web-apps)します。


![Create management API client](https://images.ctfassets.net/23aumh6u8s0i/7kPcmObqbGxBVTHj529kuG/4ba5e12bd62c077fe09c019126fc8af3/create-management-client.png)

アプリケーションの登録後、そのDomain、Client ID、およびClient Secretをメモしておきます。次に、 *Application URIs* セクションまでスクロールし、*Allowed Callback URLs* フィールドに`https://localhost:7187/onboarding/callback`を、*Allowed Logout URLs* フィールドに`https://localhost:7187/`を割り当てます。


最後に *Save Changes* をクリックして変更を確認します。

次に、アプリケーションの構成ページの *APIs* タブを選択し、Auth0 Management APIに対応するスイッチボタンを切り替えます。これでアプリケーションがそのAPIにアクセスできます。続けてAuth0 Management API項目の下の領域を展開します。


![Authorize the management API client](https://images.ctfassets.net/23aumh6u8s0i/28ocDWWx82NtO8XlY3Y2xa/4b710e133f8a8fac73ca0e9c2b5c7656/authorize-management-client.png)

ここでは、顧客のオンボーディングに必要な権限を選択する必要があります。具体的には、Organizationを作成および構成し、新しいユーザーをそれに追加する必要があります。この目的のために、次の権限を有効にします。


`read:users`, `create:users`, `update:users`, `read:organizations`, `create:organizations`, `update:organizations`, `read:organization_members`, `create:organization_members`,  `create:organization_connections`

> 原則として、テナントで実行しようとする操作に厳密に必要な権限のみを有効にしてください。


*Update* ボタンをクリックして変更を適用することを忘れないでください。


### オンボーディング用にアプリケーションを構成する


Blazorプロジェクトで`MyBlazorSaaS`フォルダにある`appsettings.json`ファイルを開き、以下に強調表示されているキーを追加します。

```json
//MyBlazorSaaS/appsettings.json

{
 "Logging": {
 "LogLevel": {
 "Default": "Information",
 "Microsoft.AspNetCore": "Warning"
 }
 },
 "AllowedHosts": "*",
 "Auth0": {
 "Domain": "YOUR_DOMAIN",
 "ClientId": "YOUR_CLIENT_ID",
 // 👇 new settings
 "ManagementClientId": "YOUR_MANAGEMENT_CLIENT_ID",
 "ManagementClientSecret": "YOUR_MANAGEMENT_CLIENT_SECRET",
 "DefaultConnectionId": "YOUR_CONNECTION_ID"
 // 👆 new settings
 }
}

```

`YOUR_MANAGEMENT_CLIENT_ID` および `YOUR_MANAGEMENT_CLIENT_SECRET`を、Auth0に登録したばかりのアプリケーションの対応する値に置き換えます。


また、アプリケーションのOrganizationsのユーザーソースとして使用する[Connection](https://auth0.com/docs/ja-jp/authenticate/identity-providers)のIDも必要です。Organizationsにユーザーを提供する方法を定義するためにさまざまな戦略を使用できますが、この記事では、デフォルトの *Username-Password-Database* connectionを使用します。したがって、Auth0ダッシュボードで、[Authentication - Database](https://manage.auth0.com/#/connections/database)をクリックし、次に *Username-Password-Database* を選択します。表示されるページで、次の図に示すように、接続名のすぐ下にある接続識別子を見つけます。

![auth0-connection-identifier](https://images.ctfassets.net/23aumh6u8s0i/6ofcqwrCn6FMqIZp04ZUHp/2c8b8f678b41b4ad07278312da037aea/auth0-connection-identifier.png)

`YOUR_CONNECTION_ID`をこの値に置き換えます。


### オンボーディングの認証とログアウトを構成する


前述のように新しい顧客がアプリケーションにサブスクライブする際、サインアップできるようにする必要があります。ただし、現在、アプリケーションはOrganizationのコンテキストでユーザーを認証するように構成されています。新しいユーザーはどのOrganizationにも関連付けられていないため、Organizationのコンテキスト外でユーザーのサインアップと認証を処理するための別のフローが必要です。


この場合、ASP.NET Core認証の観点から見ると、新しい[認証スキーム](https://learn.microsoft.com/en-us/aspnet/core/security/authentication#authentication-scheme)を構成する必要があります。以下に強調表示されているコードは、`MyBlazorSaaS`フォルダの`Program.cs`ファイルでこの新しい認証スキームを定義しています。


```csharp
//MyBlazorSaaS/Program.cs


//...existing code...

builder.Services
    .AddAuth0WebAppAuthentication(options => {
 options.Domain = builder.Configuration["Auth0:Domain"];
 options.ClientId = builder.Configuration["Auth0:ClientId"];
 options.Scope = "openid profile email";
    });

// 👇 new code
builder.Services
    .AddAuth0WebAppAuthentication("OnboardingScheme", options => {
 options.Domain = builder.Configuration["Auth0:Domain"];
 options.ClientId = builder.Configuration["Auth0:ManagementClientId"];
 options.ClientSecret = builder.Configuration["Auth0:ManagementClientSecret"];
 options.Scope = "openid profile email";
 options.CookieAuthenticationScheme = "OnboardingCookieScheme";
 options.CallbackPath = "/onboarding/callback";
    });
// 👆 new code

//...existing code...
```

上記のコードスニペットでは、Organizationのコンテキストでユーザーを認証する既存の認証スキームを確認できます。この認証スキームでは「アプリケーションの役割」で利用される構成データを使用します。


新しいコードは、アプリケーションの「オンボーディングの役割」に関する新しいアプリケーション登録の構成データを使用します。この場合、この新しい認証スキームに`"OnboardingScheme"`という名前を割り当てました。さらに、Cookie認証スキームの名前と、*Allowed Callback URLs* フィールドに登録した値の相対パスである特定のコールバックパスを追加したことがわかります。これら2つの追加オプションは、デフォルト名を使用する他の認証スキームとの競合を防ぐために必要です。


新しい認証スキームを追加したので、この認証スキームからログアウトする必要もあります。`Program.cs`ファイルで、ログアウトエンドポイントの定義を見つけ、次のコードに強調表示されているステートメントを追加します。


```csharp
//MyBlazorSaaS/Program.cs


//...existing code...

app.MapGet("/account/logout", async (HttpContext httpContext, string returnUrl = "/") =>
{
  var authenticationProperties = new LogoutAuthenticationPropertiesBuilder()
          .WithRedirectUri(returnUrl)
          .Build();

  await httpContext.SignOutAsync(Auth0Constants.AuthenticationScheme, authenticationProperties);
  await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
  // 👇 new code
  await httpContext.SignOutAsync("OnboardingScheme", authenticationProperties);
  await httpContext.SignOutAsync("OnboardingCookieScheme");
  // 👆 new code
});

//...existing code...
```

既存のログアウトステートメントと同様に、これらの新しいステートメントは、オンボーディングスキームに関連付けられた認証済みセッションを閉じます。

<include src="Auth0TemplatesForDotnetCTA" />

## サブスクリプションプロセスを開始する


オンボーディングの構成が完了した後、顧客がアプリケーションにサブスクライブして新しいOrganizationを作成できるようにする手順を実装しましょう。


`MyBlazorSaaS/Components/Layout`フォルダにある`MainLayout.razor`コンポーネントを開き、「About」マークアップを以下に強調表示されているマークアップに置き換えます。


```html
<!-- MyBlazorSaaS/Components/Layout/MainLayout.razor -->

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <Login />
            <!-- 👇 new code -->
            <a href="Onboarding/Signup">Subscribe</a>
            <!-- 👆 new code -->
        </div>

        <article class="content px-4">
 @Body
        </article>
    </main>
</div>

<!-- ...existing code --->
```

このコードは、Blazorアプリケーションの右上隅に *Subscribe* メニュー項目を追加します。その結果は次のように表示されます。

![Blazor SaaS app's home page with subscribe menu item](https://images.ctfassets.net/23aumh6u8s0i/42hxc4f88cDVqna0sNGOso/7cc6e2b3c18aa4e64f0fb17383e79889/blazor-saas-home-page-subscribe.png)

*Subscribe* メニュー項目が`Onboarding/Signup` URLを指していることがわかります。したがって、このリクエストを処理するRazorコンポーネントを実装しましょう。


`MyBlazorSaaS/Components/Pages`フォルダの下に`Onboarding`フォルダを作成します。その`Onboarding`フォルダに`Signup.razor`ファイルを作成し、次のコードを記述します。


```csharp
<!-- MyBlazorSaaS/Components/Pages/Onboarding/Signup.razor -->
  
@page "/Onboarding/Signup"
@rendermode InteractiveServer
@using System.Web
@inject NavigationManager NavigationManager

<h1>Try MyBlazorSaaS for Free</h1>
<p>
 Enter your email address to sign up and create a new organization for you and your collaborators.
</p>

<div>
  <div class="form-group row">
    <label for="email" class="col-sm-2 col-form-label">Email</label>
    <div class="col-sm-6">
      <InputText 
 type="email"
 @bind-Value="Email"
 placeholder="name@example.com"
        class="form-control"
 id="email"
 required/>
 </div>
 </div>
  <button class="btn btn-primary" @onclick="StartSignup">Get Started</button>
</div>

@code {
  private string Email = "";

  private void StartSignup()
  {
 NavigationManager.NavigateTo($"/account/signup?login_hint={HttpUtility.UrlEncode(Email)}");
  }
}
```

このコードは、オンボーディングプロセスを開始するために顧客のメールアドレスを要求します。

![Customer signup form](https://images.ctfassets.net/23aumh6u8s0i/0L4CKbrZXHiDzc2RfnWFB/a8e8e10b92edb5e163b0d30ee41ded33/customer-signup-form.png)

顧客がメールアドレスを入力して *Get Started* ボタンをクリックすると、メールアドレスをパラメータとして`/account/signup`エンドポイントにリダイレクトされます。


サインアップリクエストを処理するには、`MyBlazorSaaS`フォルダにある`Program.cs`ファイルを開き、次のコードスニペットに強調表示されているコードを追加します。


```csharp
// MyBlazorSaaS/Program.cs

//...existing code..

app.MapGet("/account/logout", async (HttpContext httpContext, string returnUrl = "/") =>
{
  //...existing code..
});

// 👇 new code
app.MapGet("/account/signup", async (HttpContext httpContext, string login_hint) =>
{
  var authenticationProperties = new LoginAuthenticationPropertiesBuilder()
          .WithRedirectUri("/onboarding/createOrganization")
          .WithParameter("screen_hint", "signup")
          .WithParameter("login_hint", login_hint)
          .Build();

  await httpContext.ChallengeAsync("OnboardingScheme", authenticationProperties);
});
// 👆 new code

app.MapGet("/api/internalData", () =>
{
  //...existing code..
}

//...existing code..
```

ここでは`/account/signup` URLへのリクエストを処理するための最小限のAPIエンドポイントを実装します。このエンドポイントは、顧客のメールアドレスを含む`login_hint`パラメータを受け取り、認証リクエストを構築します。認証リクエストが、Auth0に通常のログインフォームではなくサインアップフォームを表示するよう指示するために、[Universal Loginの`screen_hint`パラメータ](https://auth0.com/docs/ja-jp/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience#%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%A2%E3%83%83%E3%83%97) を使用していることがわかります。また、[`login_hint`パラメータ](https://auth0.com/docs/ja-jp/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience#%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3)をあわせて渡し、ユーザー名フィールドを入力しておきます。最後に、サインアッププロセスが完了した後、ユーザーをリダイレクトするURL`/onboarding/createOrganization`を指定します。


サインアッププロセスを開始するために、`httpContext.ChallengeAsync()`メソッドを呼び出します。この場合、ユーザーはOrganizationのコンテキスト外で作成および認証される必要があるため、`"OnboardingScheme"`認証スキームが指定されていることに注意してください。




> 実際のシナリオでは、Organizationの作成に進む前に、[ユーザーのメールアドレスを確認](https://auth0.com/docs/ja-jp/manage-users/user-accounts/verify-emails)する必要があります。デフォルトでは、Auth0はユーザーがサインアップすると検証リンクを含むメールを送信しますが、アクションを実行できるようにする前にメールが検証済みかどうかを確認するのはユーザー次第です。ここでは簡略化のためにメール検証を省略していますが、[顧客オンボーディングフローにメール検証ステップを追加する方法については、この記事](https://auth0.com/blog/enforce-customer-email-verification-b2b-saas-blazor-app)を参照してください。


## Auth0 Organizationを作成する


顧客がAuth0でサインアッププロセスを開始すると、アカウントが作成され、[Universal Login](https://auth0.com/docs/ja-jp/authenticate/login/auth0-universal-login)ページを通じて認証されます。ちなみに、このページはデザインニーズに合わせてカスタマイズできます。サインアップリクエストを構成したため、アカウント作成後、Organizationを作成できるページにリダイレクトされます。


### Management APIクライアントを有効にする


顧客のOrganizationを作成するには、BlazorアプリケーションがAuth0 Management APIを呼び出す必要があります。このAPIを使用すると、Auth0ダッシュボードで実行できるすべての操作をコードから実行できます。


Auth0 Management APIを使用するために、[Auth0.NET SDK](https://auth0.github.io/auth0.net/)を使用します。Auth0.NET SDKを使用すると、*管理クライアント* と呼ぶManagement APIのクライアントを作成できます。Auth0.NET SDKは2つのパッケージで構成されています。


- [Authentication API](https://auth0.com/docs/ja-jp/api/authentication)を使用してログイン、ログアウト、サインアップを処理できる *Authentication API* パッケージ。
- すべてのテナント管理操作を処理できる *Management API* パッケージ。


> .NET で利用可能なさまざまな Auth0 SDKの詳細については、[この記事](https://auth0.com/blog/choose-the-right-dotnet-sdk-for-auth0)を参照してください。




まず、次のコマンドを使用して、`MyBlazorSaaS`フォルダでホストされているBlazorサーバープロジェクトに両方のパッケージをインストールしましょう。


```bash
dotnet add package Auth0.ManagementApi
dotnet add package Auth0.AuthenticationApi
```

また、顧客が提供するOrganization名についてわかりやすいSlugを作成する必要があります。サンプルプロジェクトでは、Slugifyパッケージを使用しますが、必要に応じて別のソリューションを使用してもかまいません。Slugifyをプロジェクトにインストールするには、次のコマンドを実行します。


```shell
dotnet add package Slugify.Core
```

### Management APIクライアントを構築する


BlazorアプリケーションがAuth0 Management APIを呼び出すことができるようにするパッケージを追加した後、管理クライアントを作成しましょう。Auth0 Management APIを呼び出す必要があるたびに管理クライアントの新しいインスタンスを作成する代わりに、コードの重複を避けるだけでなく、時間とリソースを節約するのに役立つシングルトンを構築できます。この目的のために、`MyBlazorSaaS`フォルダに`Auth0Management.cs`という名前の新しいファイルを追加し、次のコードを記述します。


```csharp
using Auth0.ManagementApi;
using Auth0.AuthenticationApi;
using Auth0.AuthenticationApi.Models;

interface IAuth0Management
{
 Task<ManagementApiClient> getClient();
}

public class Auth0Management: IAuth0Management
{
  private string _domain = "";
  private string _clientId = "";
  private string _clientSecret = "";
  private ManagementApiClient managementClient = null;

  public Auth0Management(string domain, string clientId, string clientSecret)
  {
 _domain = domain;
 _clientId = clientId;
 _clientSecret = clientSecret;
  }

  public async Task<ManagementApiClient> getClient()
  {
    if (managementClient is null)
    {
      var authClient = new AuthenticationApiClient(_domain);
      var token = await authClient.GetTokenAsync(new ClientCredentialsTokenRequest
      {
 Audience = $"https://{_domain}/api/v2/",
 ClientId = _clientId,
 ClientSecret = _clientSecret
      });
 managementClient = new ManagementApiClient(token.AccessToken, _domain);   
    }
    return managementClient;
  }
}
```

ここでは、1つのメソッド`getClient()`を持つインターフェース`IAuth0Management`の定義を確認できます。


このインターフェースの下には、このインターフェースの実装クラス`Auth0Management`があります。このクラスのコンストラクタは、管理クライアントの構築に必要な3つのパラメータを受け取り、プライベート変数に格納します。


`getClient()`メソッドは、最初に管理クライアントのインスタンスが既に存在するかどうかを確認します。存在する場合は、既存のインスタンスが返されます。それ以外の場合は、認証クライアント `authClient`のインスタンスを作成し、それを使用してAuth0 Management APIのアクセストークンを取得します。この場合、[Client Credential](https://auth0.com/docs/ja-jp/get-started/authentication-and-authorization-flow/client-credentials-flow)フローを使用していることに注意してください。ここで渡しているパラメータは、オンボーディングの役割を果たすアプリケーションの登録から取得したものです。


次に、アクセストークンとAuth0ドメインを渡して管理クライアントのインスタンスを作成します。


管理クライアントをアプリケーションで使用できるようにするには、シングルトンサービスとして登録する必要があります。`MyBlazorSaaS`フォルダにある`Program.cs`を開き、次のコードを追加します。

```csharp
//...existing code..

// 👇 new code
builder.Services.AddSingleton<IAuth0Management>(sp => 
  new Auth0Management(
 builder.Configuration["Auth0:Domain"],
 builder.Configuration["Auth0:ManagementClientId"],
 builder.Configuration["Auth0:ManagementClientSecret"]
  )
);
// 👆 new code

var app = builder.Build();

//...existing code..
```

管理クライアントを構成するためにサービスコンストラクタへ渡した値に注意してください。今後、コードが管理クライアントのインスタンスを必要とする場合はいつでも、依存性注入メカニズムを利用できます。


### Organizationの作成を開始する




ここからはユーザーにOrganizationの名前を尋ね、その情報からOraganizationを作成するページの実装を開始します。


`MyBlazorSaaS/Components/Pages/Onboarding`フォルダに、`CreateOrganization.razor`という名前のRazorコンポーネントを作成し、次のコードを記述します。

```csharp
<!-- MyBlazorSaaS/Components/Pages/Onboarding/CreateOrganization.razor -->
  
@page "/Onboarding/CreateOrganization"
@rendermode InteractiveServer

@using System.Security.Claims
@using Auth0.AuthenticationApi;
@using Auth0.ManagementApi;
@using Auth0.AuthenticationApi.Models;
@using Auth0.ManagementApi.Models
@using System.Web
@using Slugify
@using Microsoft.Extensions.Configuration

@inject NavigationManager NavigationManager
@inject IConfiguration Configuration
@inject IAuth0Management auth0Management

<h1>Create an account</h1>
<p>
Enter your organization name to create an account.
</p>

<div class="my-2">
  <div class="form-group row">
    <label for="email" class="col-sm-4 col-form-label">Email</label>
    <div class="col-sm-6">
      <InputText 
 type="email"
 @bind-Value="Email"
 id="email"
        class="form-control"
 disabled/>
 </div>
 </div>

  <div class="form-group row">
    <label for="organization" class="col-sm-4 col-form-label">Organization name</label>
    <div class="col-sm-6">
      <InputText 
 @bind-Value="OrganizationName"
 placeholder="Acme Corp."
 id="organization"
        class="form-control"
 required/>
 </div>
 </div>

  <button class="btn btn-primary" @onclick="StartCreateOrganization">Create Organization</button>
</div>

@if (!string.IsNullOrWhiteSpace(Message)) {
  <div class="alert alert-danger" role="alert">
 @Message
 </div>
}

@code {
  [CascadingParameter]
  private Task<AuthenticationState>? authenticationState { get; set; }
  private string Email = "";
  private string UserId = "";
  private string OrganizationName = "";
  private string Message = "";

  protected override async Task OnInitializedAsync()
  {
    if (authenticationState is not null)
    {
      var state = await authenticationState;

      if (state.User?.Identity?.IsAuthenticated??false)
      {
 Email = state.User?.FindFirst(c => c.Type == ClaimTypes.Email)?.Value??String.Empty;
 UserId = state.User?.FindFirst(c => c.Type == ClaimTypes.NameIdentifier)?.Value??String.Empty;
      } else {
 NavigationManager.NavigateTo("/Onboarding/Signup");
      }
    }
  }

  private async Task StartCreateOrganization()
  {
    if (!String.IsNullOrEmpty(OrganizationName))
    {
 Organization organization;

      try {
        //Get management client
        var managementClient = await auth0Management.getClient();

        //Create organization
 organization = await managementClient.Organizations.CreateAsync(
          new OrganizationCreateRequest() { 
 Name = new SlugHelper().GenerateSlug(OrganizationName),
 DisplayName = OrganizationName,
 EnabledConnections = [new OrganizationConnectionCreateRequest() { ConnectionId = Configuration["Auth0:DefaultConnectionId"]}]
          }
        );

        //Add member
        await managementClient.Organizations.AddMembersAsync(
 organization.Id,
          new OrganizationAddMembersRequest() {
 Members = [UserId]
          }
        );

        // Redirect to the Organization login
 NavigationManager.NavigateTo($"/Account/Login?organizationId={organization.Id}");
      } catch (Exception ex) {
 Message = "Failed to create an organization.";
      }
    } else {
 Message = "Organization name is required.";
    }    
  }
}
```
このコードには多くの記述があります。1つずつ分析していきましょう。

まず、マークアップは次のようにレンダリングされるフォームを定義します。


![create-organization-form](https://images.ctfassets.net/23aumh6u8s0i/4bU9uFFrQGv1HXj9ErOCIn/b9a289cd710c0b6a365c7e99e85e3cec/create-organization-form.png)

`OnInitializedAsync()`メソッドは、ユーザーがこのページへアクセスしたときに実行されるチェックを定義します。

```csharp
//...existing code...

  protected override async Task OnInitializedAsync()
  {
    if (authenticationState is not null)
    {
      var state = await authenticationState;

      if (state.User?.Identity?.IsAuthenticated??false)
      {
 Email = state.User?.FindFirst(c => c.Type == ClaimTypes.Email)?.Value??String.Empty;
 UserId = state.User?.FindFirst(c => c.Type == ClaimTypes.NameIdentifier)?.Value??String.Empty;
      } else {
 NavigationManager.NavigateTo("/Onboarding/Signup");
      }
    }
  }

//...existing code...
```

ここではユーザーが認証されていることを確認します。この場合、Auth0がIDトークンを通じて提供するクレームから、ユーザーのメールアドレスとIDを抽出します。それ以外の場合、ユーザーはサインアップフォームにリダイレクトされます。


`StartCreateOrganization()`メソッドは、ユーザーが *Create Organization* ボタンをクリックすると呼び出されます。その中で実装されている主な手順について説明しましょう。


### 管理クライアントを取得する


最初の手順では、管理クライアントのインスタンスを取得します。


```csharp
//...existing code...

//Get management client
var managementClient = await auth0Management.getClient();

//...existing code...
```

ページの先頭にある`@inject IAuth0Management auth0Management`ステートメントを通じて注入された`auth0Management`インスタンスの`getClient()`メソッドを呼び出します。


### Organizationを作成する


次のステップでは管理クライアントを使用して新しいOrganizationを作成します。


```csharp
//...existing code...

organization = await managementClient.Organizations.CreateAsync(
  new OrganizationCreateRequest() { 
 Name = new SlugHelper().GenerateSlug(OrganizationName),
 DisplayName = OrganizationName,
 EnabledConnections = [new OrganizationConnectionCreateRequest() 
      { ConnectionId = Configuration["Auth0:DefaultConnectionId"]}]
  }
);

//...existing code...
```

`managementClient.Organizations.CreateAsync()`メソッドを使用し、`OrganizationCreateRequest`クラスのインスタンスを渡します。このインスタンスにはOrganizationを作成するための最小限のパラメータが含まれています。


- `Name`: Organizationの一意の論理識別子であり、変数名の規則(スペースなし、特殊文字なしなど)に従います。この識別子は、ユーザーが提供したOrganization名からSlugを生成し設定します。
- `DisplayName`: Organizationの示すわかりやすいな名前です。
- `EnabledConnections`: Organizationによって有効になっているConnectionsのリストです。この例では、この記事の冒頭で説明したデフォルトの *Username-Password-Database* connectionを追加しています。




### Organizationにメンバーを追加する


Organizationを作成した後、次のコードを使用して現在のユーザーをそのメンバーとして追加します。


```csharp
//...existing code...

await managementClient.Organizations.AddMembersAsync(
 organization.Id,
  new OrganizationAddMembersRequest() {
 Members = [UserId]
  }
);

//...existing code...
```

ここでは`managementClient.Organizations.AddMembersAsync()`メソッドを呼び出し、新しく作成されたOrganizationのIDと現在のユーザーのIDを`OrganizationAddMembersRequest`インスタンスの形式で渡します。


最後のステップでは作成したばかりのOrganizationのコンテキストでログインするようにユーザーをリダイレクトします。


```csharp
//...existing code...

NavigationManager.NavigateTo($"/Account/Login?organizationId={organization.Id}");

//...existing code...
```

このリダイレクトではユーザーはすでに認証されているため、ログインフォームは表示されません。ただし、指定されたOrganizationのコンテキストでサイレント認証されます。




### 最後のポイント


フローを完了し、新しいOrganizationへログインしたというフィードバックをユーザーに提供するため、ホームページにOrganization名を含むメッセージを追加しましょう。`MyBlazorSaaS/Components/Pages`フォルダにある`Home.razor`ページを開き、以下に強調表示されているコードを追加します。


```csharp
<!-- MyBlazorSaaS/Components/Pages/Home.razor -->

@page "/"
@inject IAuth0Management auth0Management
<!-- 👆 new code -->

<PageTitle>Home</PageTitle>

<p>
MyBlazorSaaS is a reference B2B SaaS application built using Blazor and Auth0.
</p>

<!-- 👇 new code -->
@if (!string.IsNullOrWhiteSpace(OrganizationMessage)) {
  <div class="alert alert-success" role="alert">
 @OrganizationMessage
 </div>
}
<!-- 👆 new code -->
  
<!-- ...existing markup... -->

<!-- 👇 new code -->
@code {
  [CascadingParameter]
  private Task<AuthenticationState>? authenticationState { get; set; }
  private string OrganizationMessage = "";

  protected override async Task OnInitializedAsync()
  {
    if (authenticationState is not null)
    {
      var state = await authenticationState;

      if (state.User?.Identity?.IsAuthenticated??false)
      {
        var organizationId = state.User?.FindFirst(c => c.Type == "org_id")?.Value??String.Empty;
        if (!string.IsNullOrEmpty(organizationId))
        {
          var managementClient = await auth0Management.getClient();
          var organization = await managementClient.Organizations.GetAsync(organizationId);
 OrganizationMessage = $"You are authenticated in the Organization '{organization.DisplayName}'";
        }
      }
    }
  }
}
<!-- 👆 new code -->
```

追加したマークアップは、`OrganizationMessage`変数が空でない文字列値を持つ場合に警告メッセージを表示します。ファイルの最後に追加したコードブロックは、ユーザーが認証されているかどうかを確認します。認証されている場合、ユーザーのクレームからOrganization IDを取得し、管理クライアントインスタンスを使用して現在のOrganizationの表示名を取得します。


最終的な結果は次のようになります。


![Login to Auth0 Organization](https://images.ctfassets.net/23aumh6u8s0i/2KUR94rHhq1y6dFhuwvEsR/9aa8b5b2ef9370eb221c62a0f03b91e9/login-to-auth0-organization.png)

Auth0 Organizationsの力を活用して、新しい顧客がセルフサービスでサービスにサブスクライブできる機能を最新のBlazorアプリケーションを構築できました。


<include src="SignupCTA" text="Try out Auth0 authentication for free." linkText="Get started →" />

## まとめ


これでB2B SaaSアプリケーションに新しい顧客が登録するための必要な要素が揃いました。


今回のBlog記事ではアプリケーションがAuth0コンテキストで「通常のアプリケーションの役割」と、「新しい顧客向けのオンボーディングの役割」という2つの役割を果たしていることを確認しました。


「オンボーディングの役割」では、アプリケーションはAuth0 Management APIにアクセスする権限が必要であり、新しい顧客がOrganizationのコンテキスト外で登録できるようにする必要があります。登録されると、アプリケーションはManagement APIを使用して新しい顧客向けの新しいOrganizationを作成し、その顧客をメンバーとして追加します。


この時点で、顧客のオンボーディングは完了です。新しいOrganizationで認証し、アプリケーションの機能を自由に探索できます。

