【超解説】Azure AD B2C でシングルページ Web アプリケーションを作成する

Azure AD B2C は、企業-消費者間 ID をサービスとして提供する Microsoft のサービスです。Azure AD と聞くと、どーせマイクロソフトアカウントしか使えないんでしょ？と想像する方もいらっしゃるかもしれませんが、Azure AD B2C は好みのソーシャルアカウントを使用することもできますし、ローカル ID を使用することもできます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/51b02fd6-e8d5-fe08-72b5-3fd0a13a6219.png)
今回は Microsoft が提供しているドキュメントを基に、どうやって Azure AD B2C 環境を構築するのか見ていきたいと思います。

#サンプルのリソース
今回試して見るサンプルは以下の GitHub に上がっているソースコードを使用します。Javascript ベースのシングルページアプリケーションです。
https://github.com/Azure-Samples/active-directory-b2c-javascript-msal-singlepageapp

このサンプルは既にデモの Azure AD B2C 環境で動くように作成されています。Git Clone でダウンロードして、自身のマシンで実行するとどんな感じに動くのか試すことができます。
(このアプリケーションを動かすには [Node](https://nodejs.org/en/) のインストールが必要です。)

##サンプルコードをデモ環境で実行してみる
自身で作成したオリジナルの Azure AD B2C 環境を試す前に、まずはサンプルコードそのままでデモ環境を使用して動かしてみます。
###サンプルコードを Git Clone する
Git がインストールされた環境で、以下 Git Clone を実行してみます。

```
git clone https://github.com/Azure-Samples/active-directory-b2c-javascript-msal-singlepageapp.git
```

###アプリケーションを実行する
Node がインストールされた環境かどうか確認してください。(Node -v とかで確認できます。)
クローンされたディレクトリに移動し、Node アプリケーションを以下コマンドで実行します。

```
cd active-directory-b2c-javascript-msal-singlepageapp
npm install && npm update
npm start
```
アプリケーションが実行されたら、「http://localhost:6420/」にブラウザからアクセスしてみます。以下のような Azure AD B2C の Sign In ボタンがあるような画面が表示されるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/52361e67-8ef6-e0c2-e755-a5b212852aed.png)
Sign In ボタンを押すと、以下のように、サインイン画面がポップアップウィンドウで表示されます。アドレスをみると 'fabrikamb2c' というテナントに向けてサインインを実行しているのだと推測できます。サンプルでは fabrikam というデモ用のテナントが準備されているのだとわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/7ea05eb9-9a27-9cbe-1f8c-8635bb604083.png)
これと同じ動きを、自分自身が作成したオリジナルの Azure AD B2C テナントで実行する場合の方法を次に見ていきたいと思います。

#オリジナルの Azure AD B2C 環境を使用してアプリケーションを実行する
##Azure AD B2C 環境を作成する
Azure Portal にアクセスし、新しいリソースの作成から `Azure AD B2C` を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/85d10ed2-9d7b-572c-e77e-120e869cbba9.png)
作成する Azure AD B2C の組織名、初期ドメイン名を入力して、`確認および作成` をクリックします。今回はテストとして以下の値を入力しました。

| タイトル       | 入力値     | 
| :------------- | ---------- | 
| 組織名         | mikogarage | 
| 初期ドメイン名 | mikogarage | 
| 国/地域        | 日本       | 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/7777f971-9064-c531-12d1-3963099822fe.png)
検証が無事終わると、`作成` ボタンを選択できるようになるのでクリックします。テナントの作成が開始されますが、だいたい3,4分かかるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/441696f1-d2ab-8faa-b401-6be796aba866.png)
作成されたらこんな感じの Azure AD B2C のトップページに遷移することができます。ここまでで Azure AD B2C テナントの作成は完了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/8046ce08-f850-112b-9285-bd6eeeac5499.png)

##Azure AD B2C にアプリを登録する
次に今回作成するアプリケーションを Azure AD B2C に登録します。左側のメニューの `管理` から `アプリ登録` を選択し、上の `新規登録` をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/79209aa7-11b7-f50d-6ad5-08d1b9ea848d.png)
アプリケーションの登録画面に移ります。今回は以下のように値を入力しました。

| タイトル                           | 入力値                                                                                                   | 
| :--------------------------------- | -------------------------------------------------------------------------------------------------------- | 
| 名前                               | SampleApp                                                                                                | 
| サポートされているアカウントの種類 | Accounts in any identity provider or organizational directory (for authenticating users with user flows) | 
| リダイレクト URI                   | http://localhost:6420                                                                                  | 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/3f6254cf-8309-8f06-c509-9ce48fc2502c.png)
アプリの登録が完了すると、作成したアプリの認証の部分を少し編集します。デフォルトでは、`暗黙の付与` というところにチェックが外れているので、どちらもチェックを入れ保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/3dbabc93-ddcf-644d-d1ef-49cb7e71b125.png)
ここまでで、アプリの登録は完了です。後ほどアプリのコードでこのアプリ登録したクライアントIDの情報を入力するので、`概要` に戻り、Client ID をコピペしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/09411722-ae58-dfad-aa3c-ce99b4444e80.png)

##ポリシーを作成する
ここでいうポリシーとはユーザーフローのことです。Azure AD B2C のトップに戻り、左側のメニューから、`ユーザーフロー` を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/da772083-07b3-4bd3-5500-91a625420779.png)
新しいユーザーフローを設定します。ここは GUI がしっかりしているので簡単にできると思います。ここで認証に必要な情報 (表示名や役職名など) を設定します。ユーザーフローの設定方法は以下のドキュメントにそのまままとまっているので必要に応じてご覧ください。
https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/3c788c8f-11d2-94b3-3d6d-8dd06f90acbf.png)
今回作成したユーザーフローは3つで、以下の通りです。

| ユーザーフローの名前  | タイプ                          | 
| :-------------------- | ------------------------------- | 
| B2C_1_passwordreset1  | パスワードのリセット (推奨)     | 
| B2C_1_profileediting1 | プロファイルの編集 (推奨)       | 
| B2C_1_signupsignin1   | サインアップとサインイン (推奨) | 

##API を構成する
次に、Azure AD B2C で API を使用できる環境を作成します。以下の Microsoft Docs が参考になります。
https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi
###WebAPI サンプルコードのダウンロード
以下のように Git Clone を実行して、自身のマシンにソースコードをダウンロードします。

```
git clone https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi.git
```
コードは後で編集するので、とりあえずこここではダウンロードだけでOKです！

###Azure AD B2C で WebAPI を登録する
アプリケーションの登録から、`webapi1`　という新しいアプリケーションを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/876abb6c-72f7-f0b4-a411-46b6e97209f1.png)
作成したら、左メニューの `API の公開` から アプリ ID の URI を設定します。ここでは `api` とだけ入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/4ceb9a87-37f5-3c96-1200-f6d09aa4d147.png)
###スコープの追加
次にスコープを設定します。`+ Scope の追加`　から二つの Scope を追加します。
値はこんな感じで入力しました。

| スコープ名 | 管理者の同意の表示名     | 管理者の同意の説明                  | 
| :--------- | ------------------------ | ----------------------------------- | 
| demo.read  | Read access to demo API  | Allows read access to the demo API  | 
| demo.write | Write access to demo API | Allows write access to the demo API | 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/6e0ce4d2-b5f1-40f9-0e1f-cfb1531747f4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/2a6ca6e7-ad22-f0e2-32aa-585e3db40677.png)
ふたつとも正しく入力できるとこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/630f326e-3784-9700-04ec-770c285b0835.png)

`SmapleApp` のアプリケーションに戻り、右側のメニューの `API のアクセス許可`　を選択します。ここで今追加した API を追加します。`+アクセス許可の追加` を押すと、先ほど追加した二つの API が出てくるので、二つとも選択し `アクセス許可の追加` をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/f53f61ab-73b1-68b3-f952-2cec5bee2410.png)
これだけではアクセスが付与されていません。 `XXXXX(テナント名)に管理者の同意を与えます` というボタンがクリックできるようになりますので、それをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/71651e0f-8c8d-10fa-aede-ec47004f37d0.png)
状態が緑になり、`XXXXXX(テナント名)に付与されました` と緑で出てくれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/58a14dea-4338-c2ea-bd84-aff94dbd0987.png)

###サンプルコードの編集
サンプルコードを Visual Studio Code で開きます。コードの中の `config.js` を開き以下のように編集します。

```config.js
const clientID = "253cc4e6-4b4e-4ea1-9568-ba75aa6028aa"; // webapi1 のクライアント ID に置き換える
const b2cDomainHost = "mikogarage.b2clogin.com"; //Azure AD B2C のテナント名に書き換える
const tenantId = "mikogarage.onmicrosoft.com"; // ここも同じ
const policyName = "B2C_1_signupsignin1"; //設定したポリシー名に書き換える

const config = {
    identityMetadata: "https://" + b2cDomainHost + "/" + tenantId + "/" + policyName + "/v2.0/.well-known/openid-configuration/",
    clientID: clientID,
    policyName: policyName,
    isB2C: true,
    validateIssuer: false,
    loggingLevel: 'info',
    loggingNoPII: false,
    passReqToCallback: false
}

module.exports = config;
```
API の方で変更する部分は上記の部分のみです。

###API アプリケーションを実行する
クローンしたディレクトリに移動して、以下コマンドを実行し、Web API を実行します。

```
npm install && npm update
npm start
```
実行すると色々コメントが出てきますが、アプリケーションが実行され、`Listening on port 5000` と表示されたら成功です。

```
Listening on port 5000
```
ここまでで WebAPI の方の準備が整いました。

##アプリケーションのコードを編集する
WebApp のサンプルコードは JavaScriptSPA 下の 3 つのファイルを編集します。

>apiConfig.js
authConfig.js
policies.js

```authConfig.js
const msalConfig = {
  auth: {
    clientId: "625ebccb-ed3a-4324-94db-e2681e8c8a1e", // ここを SampleApp の Client ID に変更
    authority: b2cPolicies.authorities.signUpSignIn.authority,
    validateAuthority: false
  },
  cache: {
    cacheLocation: "localStorage", // This configures where your cache will be stored
    storeAuthStateInCookie: false // Set this to "true" to save cache in cookies to address trusted zones limitations in IE (see: https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki/Known-issues-on-IE-and-Edge-Browser)
  }
};

/** 
 * Scopes you enter here will be consented once you authenticate. For a full list of available authentication parameters, 
 * visit https://azuread.github.io/microsoft-authentication-library-for-js/docs/msal/modules/_authenticationparameters_.html
 */
const loginRequest = {
  scopes: ["openid", "profile"],
};

// Add here scopes for access token to be used at the API endpoints.
const tokenRequest = {
  scopes: apiConfig.b2cScopes,  // e.g. ["https://fabrikamb2c.onmicrosoft.com/helloapi/demo.read"]
};
```

```policies.js
// Enter here the user flows and custom policies for your B2C application
// To learn more about user flows, visit https://docs.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview
// To learn more about custom policies, visit https://docs.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-overview

const b2cPolicies = {
    names: {
        signUpSignIn: "B2C_1_signupsignin1", //作成したポリシー名に変更
        forgotPassword: "B2C_1_passwordreset1", //作成したポリシー名に変更
        editProfile: "B2C_1_profileediting1" //作成したポリシー名に変更
    },
    authorities: {
        signUpSignIn: {
            authority: "https://mikogarage.b2clogin.com/mikogarage.onmicrosoft.com/B2C_1_signinsignin1", // 作成したテナント名に変更
        },
        forgotPassword: {
            authority: "https://mikogarage.b2clogin.com/mikogarage.onmicrosoft.com/b2c_1_reset",// 作成したテナント名に変更
        },
        editProfile: {
            authority: "https://mikogarage.b2clogin.com/mikogarage.onmicrosoft.com/b2c_1_edit_profile"// 作成したテナント名に変更
        }
    },
}

```

```apiConfig.js
// The current application coordinates were pre-registered in a B2C tenant.
const apiConfig = {
  b2cScopes: ["https://mikogarage.onmicrosoft.com/api/demo.read"], //作成したスコープに変更
  webApi: "https://localhost:5000" //localhost のアドレスに変更
};
```

以上の 3つでコードの編集は完了です。


#サンプルアプリを実行する
では実行してみましょう！通常の Node App と同じように `npm start` を実行します。

```
C:\Users\komiyasa\source\repos\qiita\active-directory-b2c-javascript-msal-singlepageapp>npm start

> active-directory-b2c-javascript-msal-singlepageapp@1.1.0 start C:\Users\komiyasa\source\repos\qiita\active-directory-b2c-javascript-msal-singlepageapp
> node server.js

Listening on port 6420...
```
ブラウザで 'http://localhost:6420/' にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/5bbc5c8f-785b-8597-ea32-a60a023e016c.png)
サインインボタンを押すと、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/7b2709e5-9afd-0fe3-f485-58dd702d58ac.png)
認証ウィンドウが出てきます。試しにサインアップでアドレスを入力してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/2bd57a9c-8eeb-8f0e-cfa4-5cc3ffd28caf.png)
作成したアカウントでログインできることが確認できました！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/2142c418-df9d-2049-9f26-f364bfa453f3.png)

Azure AD B2C の方の `ユーザー` で登録されたユーザーを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149921/95f0edbf-c743-559b-d5bb-156a0f48ad0e.png)

これで Azure AD B2C 認証を使用したシングルページアプリを作成することができました。
Azure AD B2C は google や Facebook といった SNS アカウントでも認証をできるので、そちらも今度試して見たいと思います。

#参考
今回参照した URL を纏めておきます。

| タイトル                                                                                       | URL                                                                                    | 
| :--------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | 
| Azure Active Directory B2C のドキュメント                                                      | https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/                           | 
| クイック スタート:Azure Active Directory B2C を使用したシングルページ アプリのサインインの設定 | https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/quickstart-single-page-app | 
| active-directory-b2c-javascript-msal-singlepageapp サンプルコード                              | https://github.com/Azure-Samples/active-directory-b2c-javascript-msal-singlepageapp    | 
| active-directory-b2c-javascript-nodejs-webapi サンプルコード                                   | https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi         | 
| チュートリアル:Azure Active Directory B2C 内にユーザー フローを作成する                        | https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/tutorial-create-user-flows | 

尚、今回作成したテナントはセキュリティの観点から既に消してあります。上記のサンプルコードをそのままコピペしても動きませんのでご了承くださいー。