Microsoft Entra Verified ID を使ってみた（③検証編）

前回の記事でVerified IDを使ったデジタル証明書の発行を行いましたが、今回は発行した証明書を検証していきます。

* [Microsoft Entra Verified ID を使ってみた（②発行編）](https://qiita.com/ToshihiroNozaki/items/ab493131998bcac837c6)

コードは Microsoft 公式で公開されているこちらを参考にしております。

https://github.com/Azure-Samples/active-directory-verifiable-credentials-dotnet

## 前提条件
* アプリケーションの動作環境は、[前回の記事](https://qiita.com/ToshihiroNozaki/items/ab493131998bcac837c6#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6)同様とします。
* Verified IDの環境構築は完了しているものとします。
  * 環境構築については[こちらの記事](https://qiita.com/AsukaSeki/items/cccc944244cd9deaeab9)をご参照ください。
* 既に前回の記事の[証明書発行](https://qiita.com/ToshihiroNozaki/items/ab493131998bcac837c6#%E8%A8%BC%E6%98%8E%E6%9B%B8%E7%99%BA%E8%A1%8C)でデジタル証明書が発行されているものとします。

## ソースコード
全体のソースコードはこちらのGitHubに公開いたしました。

https://github.com/AsukaSeki/verified-id-sample

今回Frontend, Backendの2つの実装をご紹介しますが、下記のそれぞれ下記のディレクトリ直下をご参照ください。
* Backend：`backend`ディレクトリ
* Frontend：`frontend`ディレクトリ

## まずは動かしてみる

### Frontendの起動
下記コマンドを実行し、Frontendを起動します。
* ライブラリのインストール
  ```
  > npm ci
  ```

* 実行
  ```
  > ng serve --open
  ```

### 動作確認
Frontendが起動したら、自動的に`http://localhost:4200/`にアクセスされます。

アプリケーション起動時、このようなメイン画面が表示されるため証明書の検証をしてみます。

![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/1551e54e-b37c-e266-8087-391ef6a00291.png)


### 証明書検証
証明書の検証を動かしてみます。

1. 証明書の検証画面を開くと、このようにQRコードが表示されます。発行時と同様にQRコードをモバイル端末のカメラアプリやMicrosoft Authenticatorで読み取ります。

    ![9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/c768e25a-4bc9-c913-dda6-0f7ac6fdafdc.png)

1. QRコードを読み取るとAuthenticatorで「Verifiable Credentials Expart Verifierと共有しますか？」と表示されるため、共有します。
1. 証明書の検証が完了します。アプリケーションの画面では、証明書に記載されている氏名が表示されます。

    ![12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/54e16186-b20b-bfa1-f427-f048f5861e5f.png)


#### デジタル証明書検証ページ
この画面では証明書発行ページで発行された証明書を検証します。

発行ページ同様にページにステータスを持たせ、Backendから返却されたステータスによってQRコードや証明書検証完了などの表示切り替えを行います。

1. 証明書検証ページにアクセスすると、Backendの証明書検証のリクエストAPIを呼び出します。
1. BackendからURL等が返却されたら、URLをもとにQRコードを生成し表示します。
1. 証明書検証のステータス取得API を定期的に呼び出し、「QR 読み取り中」や「検証完了」などのステータスに応じて QR コード表完了表示などに切り替えます。

## 証明書検証の概要

デジタル証明書の検証は下記の流れで行われます。ほとんど証明書の発行と同じで、違いはユーザー属性の入力やPINが無くなったくらいです。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/e04f5284-420d-5b19-bfc7-3e547632a1d3.png)

1. ユーザーはデジタル証明書検証のリクエストを依頼します。
1. Verified ID はアプリケーションへ URL を返却し、アプリケーションはそれを元に QR コードを表示します。
1. ユーザーは QR コードを読み取り、デジタル証明書の検証を許可します。
1. Verified ID は QR コードが読み取り、デジタル証明書の検証が許可されたことをアプリケーションへ通知し、アプリケーションはデジタル証明書の検証が完了したことを画面表示します。

## 実装のポイント（Backend）
Backendでは、下記のAPIを作成しています。
* 証明書検証コントローラー
  * 証明書検証のリクエストAPI
  * Verified IDからコールバックされた時のAPI
  * 証明書検証のステータス取得API

ポイントとしては証明書の発行 or 検証がまだ途中なのか、完了したのかといった状態をメモリキャッシュで保管しておき、都度この値を更新しています。

### 証明書検証コントローラー
基本的に証明書発行とソースコードは変わりませんが、Verified IDのAPIの仕様が少し異なってきます。

#### 証明書検証のリクエストAPI
* Verified IDの証明書検証APIを呼び出します。
  * 詳細：[Presentation request payload](https://learn.microsoft.com/en-us/azure/active-directory/verifiable-credentials/presentation-request-api#presentation-request-payload)
  * APIのURLは下記の通りです。
    * POST `https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createPresentationRequest`
  * Request Bodyの`callback`等は発行のAPIと同じですが、PINの要素が無くなり`requestedCredentials`という項目が追加されています。
  * APIの呼び出し成功すると、URLや有効期限が返却されます。形式は証明書発行のAPIと同じです。
    * 詳細：[Successful response](https://learn.microsoft.com/en-us/azure/active-directory/verifiable-credentials/presentation-request-api#successful-response)
* メモリキャッシュについても証明書の発行同様に、`state`をキーに持たせておきます。

![14.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/d57322a5-def5-8fb4-2a7d-d9ec71968340.png)


#### Verified IDからコールバックされた時のAPI
* ユーザーがAuthenticatorでの操作を行ったタイミングで、Verified APIからBackendへコールバックがされます。
  * 詳細：[Callback events](https://learn.microsoft.com/en-us/azure/active-directory/verifiable-credentials/presentation-request-api#callback-events)
  * `requestStatus`についてはこのような値になります。
    * QRコードが読み取られたとき：`request_retrieved`
    * 証明書が承認されたとき：`presentation_verified`
  * 証明書発行と大きく異なる点としては、証明書検証が承認されたときのコールバックの内容です。
    * `verifiedCredentialsData`が返され、その中の`claims`要素に証明書に登録したIDや氏名があります。
* このAPIでは、下記の通りコールバックされたときに`requestStatus`の値によってメモリ内の状態を更新します。
  ```csharp
  // ①QRコードが読み取られた時は「request_retrieved」が返される
  if (presentationCallback.RequestStatus == "request_retrieved")
  {
      var cacheData = new CacheData
      {
          Status = "request_retrieved",
          Message = "QR Code is scanned. Waiting for validation...",
      };
      Cache.Set(state, JsonConvert.SerializeObject(cacheData));
  }

  // ②証明書が承認された時は「presentation_verified」が返される
  if (presentationCallback.RequestStatus == "presentation_verified")
  {
      var cacheData = new CacheData
      {
          Status = "presentation_verified",
          Message = "Presentation verified",
          FirstName = presentationCallback.VerifiedCredentialsData!.First().Claims.FirstName,
          LastName = presentationCallback.VerifiedCredentialsData!.First().Claims.LastName,

          ...
      };
      Cache.Set(state, JsonConvert.SerializeObject(cacheData));
  }
  ```

![15.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/95ff6108-309f-7b6c-aefa-5cd11e29f03e.png)


#### 証明書検証のステータス取得API

* このAPIではメモリ内の状態を参照し、ステータスを返します。
* 証明書検証が完了したときに氏名を画面に表示するには、ステータスが`presentation_verified`の場合は氏名も加えて返すようにします。
  ```csharp
  if (Cache.TryGetValue(state, out string buf))
  {
      var cacheData = JsonConvert.DeserializeObject<CacheData>(buf);

      if (cacheData != null)
      {
          var result = new PresentationResponseViewModel
          {
              Status = cacheData.Status,
              Message = cacheData.Message
          };

          if (!string.IsNullOrEmpty(cacheData.Expiry))
          {
              result.Expiry = cacheData.Expiry;
          }

          if (cacheData.Status == "presentation_verified")
          {
              result.LastName = cacheData.LastName;
              result.FirstName = cacheData.FirstName;
              ...
          }

          return result;
      }
  }
  ```

## まとめ
デジタル証明書の発行と同様に、いくつかのAPIを呼び出すだけで簡単に検証もできます。

次回は、デジタル証明書の見た目についてのカスタマイズをしていきたいと思います。

## 関連記事およびサンプル
* 前回の記事
  * [Microsoft Entra Verified ID を使ってみた（①環境構築編）](https://qiita.com/AsukaSeki/items/cccc944244cd9deaeab9)
  * [Microsoft Entra Verified ID を使ってみた（②発行編）](https://qiita.com/ToshihiroNozaki/items/ab493131998bcac837c6)
* 次回の記事
  * [Microsoft Entra Verified ID を使ってみた（④証明書カスタマイズ編）](https://qiita.com/ToshihiroNozaki/items/e742781e5decb8d64383)

* [本記事のコードGitHub](https://github.com/AsukaSeki/verified-id-sample)

## 参考資料
* サンプルコード
  * [Microsoft公式GitHub](https://github.com/Azure-Samples/active-directory-verifiable-credentials-dotnet)
* 公式リファレンス
  * [Issuance request payload](https://learn.microsoft.com/en-us/azure/active-directory/verifiable-credentials/issuance-request-api#issuance-request-payload)
    * 証明書発行のAPIリクエスト