> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Auth0 連携を使用して Office 365 環境へのアクセスを提供するために、Azure AD のカスタムプロビジョニングを設定する方法について説明します。

# Office 365 カスタムプロビジョニング

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

既定の Office 365 のセットアップには Active Directory と DirSync/Azure AD Sync Services が含まれており、これらによって Azure AD 上の AD ユーザーが同期・プロビジョニングされ、<Tooltip tip="Single Sign-On (SSO): ユーザーが1つのアプリケーションにログインすると、その後ほかのアプリケーションにも自動的にログインできるようにするサービス。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=SSO">SSO</Tooltip> が実現されます。この構成では、Auth0 が <Tooltip tip="Single Sign-On (SSO): ユーザーが1つのアプリケーションにログインすると、その後ほかのアプリケーションにも自動的にログインできるようにするサービス。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=identity+provider">アイデンティティプロバイダー</Tooltip> となり、これらのユーザーにシングルサインオン (SSO) を提供します。

では、業務委託先、パートナー、あるいは顧客にも Office 365 環境 (たとえば SharePoint) へのアクセスを許可したい場合はどうすればよいでしょうか。この場合、既定の方法は最適ではありません。というのも、これらのユーザーを AD 環境内に作成する必要があるためです。代わりに、[Auth0 ルール](/docs/ja-jp/customize/rules) を使用して Azure AD ユーザーをカスタムでプロビジョニングする必要があります。

カスタムプロビジョニングを使用すると、Auth0 で利用可能な任意の接続からユーザーがログインしたタイミングで、Azure AD (ひいては Office 365) にユーザーを作成できます。 (この場合、DirSync で対応できない種類の接続については、ルールが DirSync の役割を引き継ぎます。) この構成により、Office 365 環境に対してさまざまなログインオプション (Facebook、LinkedIn、Google Workspace など) を提供できます。

<div id="prerequisites">
  ## 前提条件
</div>

カスタム プロビジョニングを設定する前に、次のことを行う必要があります。

* [Office 365 を設定する](https://marketplace.auth0.com/integrations/office-365-sso): <Tooltip tip="カスタム ドメイン: 専用名またはバニティ名を持つサードパーティのドメイン。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=custom+domain">カスタム ドメイン</Tooltip>を登録し、Auth0 で Office 365 をサードパーティアプリケーションとして設定します。

<div id="configure-azure-ad">
  ## Azure AD を構成する
</div>

カスタム プロビジョニングでは、Azure AD Graph API を使用して Azure AD に新しいユーザーをプロビジョニングします。Azure AD Graph API にアクセスするには、Office 365 サブスクリプションにリンクされた Azure AD Directory 内でアプリケーションを作成する必要があります。

1. [Azure Portal](https://portal.azure.com) にログインします。
2. [左側のナビゲーションにある Azure Active Directory](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview) を選択します。
3. 新しいメニューで **App registrations** を選択します。
4. **New application registration** をクリックします。
5. フォームに入力します。

   1. アプリケーション名を入力します (`Auth0 Provisioning` など)
   2. **Application type** として **Web app / API** を選択します。
   3. サインオン URL を入力します。有効な URL であればどれでもかまいません。実際に使用されることはありません。
6. 作成したアプリケーションが **App registrations** の一覧に表示されるので、それを選択します。
7. **Settings** ブレード (Microsoft ではこれらのセクションを「blades」と呼びます) で、**Keys** を選択します。
8. **Description** (`Auth0 Provision` など) を入力し、新しいキーの **Duration** を選択します。無期限ではないキーを発行する場合は、有効期限を控えておき、期限切れになる前に新しいキーに置き換えられるようリマインダーを設定してください。
9. クリックしてキーを保存し、**App Key** をコピーします。このキーが表示されるのは一度だけで、Auth0 ルールで必要になります。
10. **Required permissions** を選択し、新しいブレードで **Add** をクリックします。
11. **Microsoft Graph** API を選択し、**Application Permissions** の下にある `Read and write directory data` にチェックを入れます。
12. **Required permissions** に戻り、**Grant Permissions** ボタンをクリックしてから、要求された権限を付与するために **Yes** をクリックします。

<div id="create-the-azure-ad-provisioning-rule">
  ## Azure AD のプロビジョニングルールを作成する
</div>

次のルールは、プロビジョニングの流れを示しています。

1. ユーザーが AD 接続経由の場合は、プロビジョニング処理をスキップします (これは DirSync によって処理されるためです) 。
2. ユーザーがすでに Azure AD にプロビジョニングされている場合は、そのままログイントランザクションを続行します。
3. Azure AD の Client ID と Key を使用して、Graph API 用のアクセストークンを取得します。
4. Azure AD にユーザーを作成します。
5. ユーザーにライセンスを割り当てます。
6. ログイントランザクションを続行します。

ユーザー名は `createAzureADUser` 関数によって生成されます。デフォルトでは、`auth0-c3fb6eec-3afd-4d52-8e0a-d9f357dd19ab@fabrikamcorp.be` の形式のユーザー名が生成されます。これは任意の値に変更できますが、すべてのユーザーで一意になるようにしてください。

設定オブジェクト内の `AUTH0_OFFICE365_CLIENT_ID`、`AAD_CUSTOM_DOMAIN`、`AAD_DOMAIN`、`AAD_APPLICATION_ID`、`AAD_APPLICATION_API_KEY` に正しい値を設定し、それらの値をルールコードで利用できるようにしてください。詳しくは、[Store Configuration for Rules](/docs/ja-jp/customize/rules/configuration) をご覧ください。

コードを見ると、ユーザーのプロビジョニング後にルールが約 15 秒待機することもわかります。これは、プロビジョニングされたユーザーが Office 365 で利用可能になるまでに数秒かかるためです。

```javascript lines expandable theme={null}
function (user, context, callback) {
  // 使用するNode.jsパッケージを読み込みます。
  // 利用可能なパッケージの完全なリストはこちらのウェブサイトをご確認ください:
  // https://auth0-extensions.github.io/canirequire/
  var rp = require('request-promise');
  var uuidv4 = require('uuid');

  // Active Directory接続の名前（使用している場合）
  var AUTH0_AD_CONNECTION = 'Travel0AD';
  // Office 365 SSO統合のclient_id
  // SSO統合の編集画面のURLから取得できます。
  // URLは以下のような形式になります:
  // https://manage.auth0.com/#/externalapps/{the_client_id}/settings
  var AUTH0_OFFICE365_CLIENT_ID = configuration.AUTH0_OFFICE365_CLIENT_ID;
  // 会社のメインドメイン。
  var YOUR_COMPANY_DOMAIN = 'mycompanyurl.com';
  // Azure ADのドメイン。
  var AAD_DOMAIN = configuration.AAD_DOMAIN;
  // Azure ADアプリ作成時に生成されたアプリケーションID。
  var AAD_APPLICATION_ID = configuration.AAD_APPLICATION_ID;
  // Azure ADアプリ用に生成されたAPIキー。
  var AAD_APPLICATION_API_KEY = configuration.AAD_APPLICATION_API_KEY;
  // Microsoft製品にアクセスするユーザーの所在地。
  var AAD_USAGE_LOCATION = 'US';
  // Azure ADはユーザーを即座に認識しないため、数秒の待機が必要です
  var AAD_USER_CREATE_DELAY = 15000;
  // 新規ユーザーに付与するライセンスを表すキー。
  // 既存のライセンス一覧は以下のURLを参照してください:
  // https://gist.github.com/Lillecarl/3c4727e6dcd1334467e0
  var OFFICE365_KEY = 'O365_BUSINESS';

  // このルールはOffice 365 SSO統合に対してのみ実行します。
  if (context.clientID !== AUTH0_OFFICE365_CLIENT_ID) {
    return callback(null, user, context);
  }

  // ADユーザーのカスタムプロビジョニングをスキップします。
  if (context.connection === AUTH0_AD_CONNECTION) {
    return callback(null, user, context);
  }

  // ユーザーがすでにMicrosoft ADにプロビジョニングされている場合、
  // このルールの残りの処理をスキップします
  user.app_metadata = user.app_metadata || {};
  if (user.app_metadata.office365Provisioned) {
    return connectWithUser();
  }

  // 新規ユーザーのプロビジョニング中に各ステップで使用するグローバル変数。
  var token;
  var userPrincipalName;
  var mailNickname = user.email.split('@')[0];
  var uuid = uuidv4.v4();
  var immutableId = new Buffer(uuid).toString('base64');
  var userId;

  // Microsoft ADの新規ユーザーをプロビジョニングするための全ステップ。
  // 各関数の定義は以下に記載しています。
  getAzureADToken()
    .then(createAzureADUser)
    .then(getAvailableLicenses)
    .then(assignOffice365License)
    .then(saveUserMetadata)
    .then(waitCreateDelay)
    .then(connectWithUser)
    .catch(callback);

  // Windows Graph APIと通信するためのアクセストークンをリクエストします。
  function getAzureADToken() {
    var options = {
      method: 'POST',
      url: 'https://login.windows.net/' + AAD_DOMAIN + '/oauth2/token?api-version=1.5',
      headers: {
        'Content-type': 'application/json',
        },
      json: true,
      form: {
        client_id: AAD_APPLICATION_ID,
        client_secret: AAD_APPLICATION_API_KEY,
        grant_type: 'client_credentials',
        resource: 'https://graph.windows.net'
      },
    };

    return rp(options);
  }

  // 上記でリクエストしたアクセストークンを取得し、
  // Microsoft ADの新規ユーザーをプロビジョニングするリクエストを組み立てます。
  function createAzureADUser(response) {
    token = response.access_token;
    userPrincipalName = 'auth0-' + uuid + '@' + YOUR_COMPANY_DOMAIN;

    var options = {
      url: 'https://graph.windows.net/' + AAD_DOMAIN + '/users?api-version=1.6',
      headers: {
        'Content-type': 'application/json',
        'Authorization': 'Bearer ' + token
      },
      json: true,
      body: {
        accountEnabled: true,
        displayName: user.nickname,
        mailNickname: mailNickname,
        userPrincipalName: userPrincipalName,
        passwordProfile: {
          password: immutableId,
          forceChangePasswordNextLogin: false
        },
        immutableId: immutableId,
        usageLocation: AAD_USAGE_LOCATION
      },
    };

    return rp(options);
  }

  // ユーザーのプロビジョニング後、利用可能なMicrosoft製品ライセンスの
  // 一覧を取得するリクエストを発行します。
  function getAvailableLicenses(response) {
    userId = response.objectId;
    var options = {
      url: 'https://graph.windows.net/' + AAD_DOMAIN + '/subscribedSkus?api-version=1.6',
      json: true,
      headers: {
        'Content-type': 'application/json',
        'Authorization': 'Bearer ' + token
      }
    };
    return rp(options);
  }

  // ライセンス一覧を反復処理して、新規ユーザーに付与するライセンス
  //（この場合はOffice 365）のID（skuId）を取得します。
  // さらに、Graph APIに新たなリクエストを発行して、ユーザーとライセンスを
  // 紐付けます。
  function assignOffice365License(response) {
    var office365License;

    for (var i = 0; i < response.value.length; i++) {
      if (response.value[i].skuPartNumber === OFFICE365_KEY) {
        office365License = response.value[i].skuId;
        break;
      }
    }

    var options = {
      url: ' https://graph.windows.net/' + AAD_DOMAIN + '/users/' + userId + '/assignLicense?api-version=1.6',
      headers: {
        'Content-type': 'application/json',
        'Authorization': 'Bearer ' + token
      },
      json: true,
      body: {
        'addLicenses': [
          {
            'disabledPlans': [],
            'skuId': office365License
          }
        ],
        'removeLicenses': []
      }
    };
    return rp(options);
  }

  // ユーザーのプロビジョニングとライセンスの付与が完了したら、
  // このGoogle WorkspaceユーザーがすでにプロビジョニングされたことをAuth0に記録します。
  // また、今後のログイン時に適切にリダイレクトできるよう、ユーザーのプリンシパル
  // ユーザー名とimmutableIdも記録します。
  function saveUserMetadata() {
    user.app_metadata = user.app_metadata || {};

    user.app_metadata.office365Provisioned = true;
    user.app_metadata.office365UPN = userPrincipalName;
    user.app_metadata.office365ImmutableId = immutableId;

    return auth0.users.updateAppMetadata(user.user_id, user.app_metadata);
  }

  // 前述のとおり、Windows Graph APIは新規ユーザーのプロビジョニング完了に
  // 約10秒かかります（即座にOKを返す場合でも同様です）
  function waitCreateDelay() {
    return new Promise(function (resolve) {
      setTimeout(function() {
        resolve();
      }, AAD_USER_CREATE_DELAY);
    });
  }

  // プリンシパルユーザー名とimmutableIdをユーザーオブジェクトに追加し、
  // ルールを終了します。
  function connectWithUser() {
    user.upn = user.app_metadata.office365UPN;
    user.inmutableid = user.app_metadata.office365ImmutableId;
      return callback(null, user, context);
  }
}
```

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  このコードは新規ユーザーのプロビジョニング処理を示していますが、既存ユーザーのメタデータを同期するように変更することもできます。
</Callout>

<div id="user-experience">
  ## ユーザー エクスペリエンス
</div>

外部ユーザーが認証する最も簡単な方法は、Identity Provider 主導ログインを利用することです。

ユーザーを次の URL にリダイレクトする必要があります (例: `https://office.travel0.com` のような「スマートリンク」を使用) :

export const codeExample = `https://{yourDomain}/login?client=AUTH0_OFFICE365_CLIENT_ID&protocol=wsfed&state=&redirect_uri=&`;

<AuthCodeBlock children={codeExample} language="http" />

これにより、まず Auth0 のログインページが表示され、その後 Office 365 にリダイレクトされます。Office 365 のログインページは、これらの外部ユーザー向けの Home Realm Discover をサポートしていないため、外部ユーザーには、この方法でしか認証できないことを説明しておくことが重要です。つまり、ユーザーがリンクを開こうとした場合、開こうとしたリンクにアクセスする前に、まずスマートリンクにアクセスする必要があります。

この例では、Travel0 は Auth0 で、Office 365 用のサードパーティアプリケーションに対して、いくつかのソーシャルアカウントとデータベース接続を有効にしています。

<div id="deep-linking">
  ## ディープリンク
</div>

実装によっては、ディープリンク (たとえば SharePoint Online へのリンク) が必要になる場合があります。この場合は、Office 365 のログインページを起点とするスマートリンクを構築する必要があります。

```http wrap lines theme={null}
https://login.microsoftonline.com/login.srf?wa=wsignin1.0&whr={yourCustomDomain}&wreply={deepLink}
```

最初のパラメータ `{yourCustomDomain}` には、Azure AD で <Tooltip tip="ユーザーが1つのアプリケーションにログインした後、そのユーザーを他のアプリケーションにも自動的にログインさせるサービス。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=Single+Sign-on+%28SSO%29">Single Sign-on (SSO)</Tooltip> 用に設定したドメイン (例: `travel0.com`) を指定します。これを `whr` として指定すると、Azure AD はログインページを表示する代わりに、Auth0 にリダイレクトする必要があることを認識します。

`DEEP_LINK` パラメータには、Office 365 内のエンコードされた URL (たとえば、SharePoint Online や Exchange 内のページ) を指定する必要があります。

URL の例:

```http wrap lines theme={null}
https://login.microsoftonline.com/login.srf?wa=wsignin1.0&whr=travel0.com&wreply=https%3A%2F%2Ftravel0%2Esharepoint%2Ecom
```
