🃏

Microsoft Entra Verified ID の動きをみてみた。発行編

2022/12/16に公開

Digital Identity技術勉強会 #iddance Advent Calendar 2022 16 日目の記事です。

Microsoft Entra Verified ID が GA になりましたので、とりあえずチュートリアルを動かしてみたら普通に VC (Verifiable Credentials) を発行 / 検証できたけど、この二つのフローが長いし参加しているアクターも多く、かつマネージド サービスにつきわかりづらい部分が多かったので、フロー全体を少し細かくみてみました。

本記事は 3 部構成で、MS Verified ID サービスを使った VC の発行(Issuance、本記事)、 検証(Verification) および 取消(Revocation) の流れについてそれぞれ説明します。
今回はまず VC 発行のフローについて説明します。

Disclaimer

本記事では Microsoft Verified ID の使い方、VC を発行/検証するための MS Entra (Azure AD) まわりの構成の話、あるいは RP の実装に関する細かい話はしません。VC を発行してみたい!と思う方はまず以下の公式チュートリアルを動かしてみるといいと思います。

  1. Tutorial - Configure your tenant for Azure AD Verifiable Credentials

  2. Tutorial - Issue Azure AD Verifiable Credentials from an application

  3. Tutorial - Configure Azure AD Verifiable Credentials verifier

また、Microsoft Entra Verified ID の全体的なアーキテクチャをある程度把握するためには、aka.ms/didfordevs まず一通り目を通すことをおすすめします。

MS Verified ID は VC 関連の様々な標準仕様の策定に参加しており、W3C / OIDC / DIF の標準仕様に沿って実装していると思いますが、(MS 内部的にどのような実装されているか確認できない部分もあり、私のスキル不足の部分もあるため)仕様に関する細かい話(フローのどの部分でどういった仕様を沿って実装されているか、最新の仕様をどこまで追いついているか等)についてはしません。

なお記事の中に間違った記述がありましたら、ご指摘いただけますと訂正しますし、非常にうれしく思います。

VC 発行フロー

それでは、MS Verified ID を使った VC の発行の全体の流れをみてみましょう。

各アクターの紹介

まず、上記シーケンス図にある各アクターの役割を紹介します。

  • Authenticator: VC を保存する Wallet (Holder) のこと。 MS Verified ID の場合、MS Authenticator アプリを利用するのが一般的ですが、必須ではありません。
  • Web Browser: Chrome, Firefox 等一般的な Web ブラウザーとなります。機能的にごく一般的な Web ページを表示できればいいので、バージョン等の制約はありません。
  • Web App: いわゆる RP のことになります。VC を発行するパーティー(Issuer)または VC を検証するパーティー(Verifier)となります(※ MS Verified ID のエコシステムでは、Issuer / Verifier が自前で VC を発行 / 検証ではなく、実際やるのは MS Verified ID となりますので、Web App はあくまでもユーザー/Wallet と MS Verified ID の仲介役となります)。
  • MS Entra Verified ID: Microsoft が提供する Verified Credentials の各操作を提供するマネージド サービスとなります。
  • ION: シーケンス図には記載されていないが、ION に保存している Issuer の DID を resolve するために、MS Verified ID サービスは内部的に ION と通信していると思われます。ION についてそれほど詳しくないですが、Bitcoin ブロックチェーンの上に動作する Layer 2 の分散型 ID ネットワークと認識しています。ION の詳細については こちら をご覧ください。

VC 発行フローの詳細

それでは、シーケンス図の各ステップを細かく見てみましょう。

(1) VC を発行したいユーザーが Web サイトにアクセスして、「VC 発行」みたいなボタンをクリックします。

例えば、とある学校は学位証明書を VC として発行することができるとします。
学位証明書(VC)を申請する学生は、学校のホームページにアクセスして、VC を申請します。
この場合、Web App は学校の VC 申請ページを表示する Web アプリケーションになります。

申請者は Web App で認証したかもしれませんし、認証しないシナリオもあり得ます。

Web App に「学位証明書申請」ボタンが存在すると想定して、申請者はこのボタンをクリックしたら、VC 発行フローがキックオフされる想定になります。

※ 当方 Westworld というドラマがすきですので、作ったサンプル アプリケーションは Westworld をモチーフとしたものです。学位証明書と一ミリも関係ありません。すみません。

(2) Web App は MS Verified ID の Issuance API に VC 発行要求を送信します。

MS Verified ID サービスは、実際の Issuer (上記例の中の "学校")の代わりに VC を発行 / 検証 しますので、Web App は MS Verified ID に対して、VC 発行要求を送信します。
実際リクエスト送信対象となり API は以下になります。

API Reference
https://learn.microsoft.com/ja-jp/azure/active-directory/verifiable-credentials/issuance-request-api#http-request

また、送信するリクエストの一例(ID Token Hint attestation)は以下です。

POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createIssuanceRequest
Content-Type: application/json
Authorization: Bearer <token>
{
  "includeQRCode": true,
  "callback": {
    "url": "https://www.contoso.com/api/issuer/issuanceCallback",
    "state": "de19cb6b-36c1-45fe-9409-909a51292a9c",
    "headers": {
      "api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
    }
  },
  "authority": "did:ion:EiCLL8lzCqlGLYxxxxxxxxxxxxxxxxxxxxxx5zM7fQZ8Jg:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpb24iOiJyZXBsYWNlIiwiZG9jdW1lbnQiOnsicHVicxxxxxxxxxxxxxxxLCJ4IjoiTEdUOWk3aFYzN1dUcFhHcUg5c1VDek",
  "registration": {
    "clientName": "Sample"
  },
  "type": "VerifiedCredentialExpert",
  "manifest": "https://verifiedid.did.msidentity.com/v1.0/12345678-0000-0000-0000-000000000000/verifiableCredentials/contracts/VerifiedCredentialExpert",
  "claims": {
    "given_name": "Megan",
    "family_name": "Bowen"
  },
  "pin": {
    "value": "3539",
    "length": 4
  }
}

この API を呼び出せるのは、あくまでも MS Verified ID サービスを利用する正当な Issuer のみなので、Issuer があらかじめこの API を呼び出すためのアクセス トークンを取得して、Authorization Header に設定する必要があります。

このアクセス トークンは、Web App があらかじめ MS Verified ID サービスに定義した OAuth 2.0 クライアントの資格情報を利用して、OAuth 2.0 Client Credentials Grant より Azure AD から取得します。

このあたりの事前準備はフローに関係ないので割愛します。チュートリアルを動かせばなんとなく理解できると思います。

補足

Issuance Request の各パラメータの意味は API ドキュメントに詳しく記載していますので細かく説明しませんが、何点か補足します。

state
MS の VC 発行フローは、Web App が MS にリクエストを送信した後に、MS は Authenticator とやり取りして、その間に Web App は MS に polling して、MS <> Authenticator のやり取り結果(状態の変化)を確認します。
state パラメータは、Web App が送信するリクエストと polling 結果の整合性を確保する(binding する)ためのパラメータになります。

authority
Issuer の DID になります。この DID は、MS Entra ポータル - 検証済みのID - 組織の設定 - 分散化識別子 (DID) から確認できます。

manifest
VC 発行に Credential Manifest を取得するための URL になります。この URL も MS Entra Portal から確認可能です。
Manifest の中身は、MS Entra ポータルから設定する 表示の定義 & ルールの定義 の内容より構成されます。

注意点

createIssuanceRequest に投げる payload に含まれるパラメータは、Attestation 方式によって変わります。当然ではありますが、payload の内容を適当に構成してしまうと後ほど VC の発行が失敗します。

上記例は ID Token Hint Attestation を利用時の payload となりますが、例えば ID Token Attestation を利用する場合、外部 OP から別途 ID Token を取得するため、Web App から MS Verified ID に送る payload に claim の記載は不要です。
記載してしまうと、この API コールは失敗しませんが、後ほど Authenticator から VC を取得する際にエラーが起きると思われます。

また、Manifest (表示の定義 & ルールの定義)の定義も当然ながら正しく MS に登録しなければなりません。
典型的な失敗例として、Claim Mapping の設定に誤りがあり、Attestation 時に MS Verified ID が Manifest の定義とおり ID Token から Claim を取得しようとするときに、該当 Claim が ID Token に存在してなくて VC が発行できなくなることが挙げられます。

VC 発行のプロセスに手順が多く、自分が持つ Web サーバー以外のところ(Authenticator <> MS Verified ID みたいなところ)に通信も発生するため、デバッグが難しいです。
MS Autheticator には一応ログをダンプする機能があるけど、ログがローテートされないし検索機能もないので、ほぼ使えないです。
デバッグのため Authenticator とともに携帯端末に Charles / Fiddler とか通信トレースを取るアプリを入れとくといいかもしれません。

(3) MS Verified ID サービスは、Web App に Issuance Request の応答を返します。

応答の一例として、以下の形のレスポンスが Web App に返されます。

{
  "requestId":"0b3a9f6e-1bc0-4028-bbaf-e482d86a9dc6",
  "url":"openid-vc://?request_uri=https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/request/0b3a9f6e-1bc0-4028-bbaf-e482d86a9dc6",
  "expiry":1669185828,
  "pin":"7491",
  "id":"a94e9202-04e4-49ba-9293-0c2d160d3d21"
}

(4) Web App は QR コードを生成します。

(5) Web ブラウザーがユーザーに QR コードを表示します。

Web App は (3) の応答にある url パラメータを QR コードの形式で Web ブラウザー上で表示し、URL を Authenticator に読み込ませます。

MS Verified ID が VC を発行するため、VC カードに追加するユーザーの Claim を取得する必要があります。
MS Verified ID の実装では、OpenID Connect なプロトコルに従い、取得した ID Token にあるユーザー Claim を利用します。
ここで利用/策定したプロトコルは、Self-Issued OP (SIOP) V2 となります。

MS Verified ID が OpenID Connect でいう RP として、Authenticator は OP としてふるまい、Attestation を行うことでユーザーの属性情報を取得した後に、その属性情報が含まれている ID Token を SIOP のレスポンスにて MS Verified ID 返します。

また、今回のシナリオでは、OP / RP は別々の端末になるため、RP から OP へ Authorization Request の送信は、前述 SIOP V2 の Cross-Device Self-Issued OP に定義されている「QR コード」読み取り方式となります。

この方式では、RP (Web App) が (3) の payload の url にある openid-vc://?request_uri=xxx みたいな URL を QR コードとして生成し、OP である Authenticator に読み取らせることで、RP から Authorization Request を OP に渡します。

QR コードの生成は、別に特殊な要件がなく、上記 URL が含まれていればよいです。

補足 1

OpenID Connect プロトコルの上に VC 発行のためのプロトコルとして、OpenID for Verifiable Credential Issuance という仕様は現在策定中です(2022年末までに First Implementater's Draft の完成を目指しているらしい)。
Microsoft を含む各ベンダーはこの仕様を実装する予定/実装中らしいですので、Microsoft Verified ID においても今後新しい機能やフローが出てくるかもしれません。

補足 2

Passkey の Hybrid Transport (aka caBLE) 等、最近 QR コードを利用する Cross Device な Authz フローのユースケースが増えた関係かもしれませんが 、ちょうど数週間前に Cross-Device Security Best Current Practice というドラフトが WG に adopt されるかみたいな話がありましたね。

SIOP V2 のこのユースケースもこのトピックの対象になりますので、時間がありましたらここらへんのセキュリティ周りの仕組みや MS の Mitigation の方法をもうちょっと整理したいと思いました(独り言)。

(6) Web ブラウザーは Web App に対して Polling を実施します。

Web App が VC を発行するための QR コードを Authenticator に提供したあとに、基本的にやることがありません。
これからは主に Authenticator と MS Verified ID の間でやり取りして、MS Verified ID から Authenticator に VC を発行します。

しかし Web App の UI/UX としては、現在 VC 発行の状態を取得して、ブラウザー上に反映したいですし、発行成功後に後続処理をしたい可能性もあります。
そのため、MS Verified ID サービスは VC 発行の状態変化を Web App に通知する仕組みを提供しています。

Web App の実装上、フロントエンド(javascript 等)からバックエンド API に対して Polling し、現在 VC 発行のステータスを取得します。
Web App バックエンドが expose する API は、MS Verified ID から受け取った通知を API のレスポンスに反映して、フロントエンドに伝えます。

これはあくまでも Web App の実装(UI/UX 寄り)の話になりまして、必ずしも実施する必要がないです(少なくとも VC 発行自体には影響しません)。
※ MS が提供しているチュートリアルやサンプルコードでは、このような Polling の仕組みを実装しています。

(7) ユーザーは Authenticator アプリを使って QR コードをスキャンします。

MS Authenticator アプリの 検証済み ID タブの右上に、QR コードを読み取るボタンがあります。
ユーザーはそのボタンをタップして、Web App 上で表示された QR コードを読み取ります。

これで Authenticator が RP の Authorization Request を受け取るための URL を取得できました。


完全に余談ですが、MS Verified ID サービスを利用するには、Wallet として MS 製の Authenticator を使うのが一般的ではありますが、必須条件ではありません。
MS は Wallet を実装するための SDK を提供しており(現時点ではプレビュー版)、ご自身で Wallet アプリを作ることも可能です(もちろん、SDK を使わなくても実装可能です)。

(8) Authenticator は request_uri から Authorization Request をダウンロードします。

ダウンロードした Authorization Request は JWT 形式のものになります。

ID Token Hint attestation の場合、Authenticator が取得した Authorization Request (デコード後)の一例は以下です。

{
  "alg": "ES256K",
  "kid": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
  "typ": "JWT"
}.{
  "jti": "2b6420fd-dcb2-46ee-8205-25bd587e8f52",
  "iat": 1670399240,
  "response_type": "id_token",
  "response_mode": "post",
  "scope": "openid",
  "nonce": "kRxK63dJGuhzRIsahUUZkA==",
  "client_id": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "redirect_uri": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/issuance",
  "prompt": "create",
  "state": "djGT2Tf1KttUJiVB3SGIdIuLZqwly17RQ+zrdBANqwJwilOv8cSTkNIWNytgZKB6X/pfpIGBBj0KCsUw==",
  "exp": 1670399540,
  "registration": {
    "client_name": "Sample",
    "subject_syntax_types_supported": [
      "did:ion"
    ],
    "vp_formats": {
      "jwt_vp": {
        "alg": [
          "ES256K"
        ]
      },
      "jwt_vc": {
        "alg": [
          "ES256K"
        ]
      }
    }
  },
  "claims": {
    "vp_token": {
      "presentation_definition": {
        "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "input_descriptors": [
          {
            "id": "Sample",
            "schema": [
              {
                "uri": "Sample"
              }
            ],
            "issuance": [
              {
                "manifest": "https://verifiedid.did.msidentity.com/v1.0/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/contracts/MzAxMjUzZjQtYzIyMC00MWI3LTgwNWEtZTNiOTAyNGZkM2Q0YmVybmFyZGlkcA/manifest"
              }
            ]
          }
        ]
      }
    }
  },
  "pin": {
    "length": 4,
    "type": "numeric",
    "hash": "HXztsPMNHhcapSi45X7u82XxUWdWW5Q0sTkCZ/cXtts="
  },
  "id_token_hint": "eyJxxxxxxxxxxxxxxxxxxxxxxxx"
}.[Signature]

なんとなく OpenID Connect の Authorization Request なパラメータが分かります。

  • response_mode=post は SIOP V2 で新しく定義されたもので、response_type=id_token と合わせて、ID Token を HTTP Post で redirect_uri に返すことを示します。
  • redirect_uri は VC 発行するための MS Verified ID のエンドポイントになります。
  • id_token_hint に Web App が MS Verified ID に送信する Issuance Request に申告したユーザー Claim が含まれているID Token が含まれていることも確認でいます。ID Token は MS Verified ID サービスが "Self-Issued" したもので、Issuer の DID に紐づく 秘密鍵で署名されます。ID Token デコード後の一例は以下になります。
{
  "alg": "ES256K",
  "kid": "did:ion:EiALbbi7GmTRpazZBxxxxxxxxxxxxxxxUXFQk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpxxxxxxxxxxxxxxxxVQRHJTLTVCSS1rS0NuWExIa3kzYmQwODU3RkthX0dBIn19#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
  "typ": "JWT"
}.{
  "sub": "bEgvmzgxE21GH81wTOi_zYngAFDQ29EwGofC8iJJoAc",
  "aud": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/card/issue",
  "nonce": "h6bXq8/kK2ORrnB2AXqX1Q==",
  "sub_jwk": {
    "crv": "secp256k1",
    "kid": "did:ion:EiALbbi7GmTRpazZBxxxxxxxxxxxxxxxUXFQk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpxxxxxxxxxxxxxxxxVQRHJTLTVCSS1rS0NuWExIa3kzYmQwODU3RkthX0dBIn19#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
    "kty": "EC",
    "x": "Txf25KNr19URFPtMT9eL_idygUfD9y0waAOicXI9aIk",
    "y": "pqOrwAZSBUrnf7NOQabh4OVKLkf1NUeloBwjIB5DU18"
  },
  "did": "did:ion:EiALbbi7GmTRpazZBxxxxxxxxxxxxxxxUXFQk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpxxxxxxxxxxxxxxxxVQRHJTLTVCSS1rS0NuWExIa3kzYmQwODU3RkthX0dBIn19",
  "given_name": "Xxxxxxxx",
  "family_name": "Xxxxx",
  "iss": "https://self-issued.me",
  "iat": 1670484130,
  "jti": "1bee385d-a1cb-4035-aa7c-732775e00b8f",
  "exp": 1670484430,
  "pin": {
    "length": 4,
    "type": "numeric",
    "hash": "7uY8JKr6SwxxxxxxxxxxZIp6Tv7pnvk="
  }
}.[Signature]

上記 Authorization Request にもう一つ重要なパラメータは presentation_definition です。その中に VC issuance 時の manifest の URL があります。

(9) Authenticator は Issuer の DID を Resolve します。

Authorization Request の client_id クレームには、SIOP RP(Issuer)の DID になります。Authenticator は Issuer の DID を取得した後に、MS Verified ID が提供している Discovery エンドポイントに DID を送信して、Issuer の DID を Resolve します。

Issuer の DID は ION に保存されているため、内部的に MS Verified ID サービスはおそらく ION と通信して DID を resolve しています。

以下は MS Verified ID Discovery エンドポイントに送るリクエスト/レスポンス例となります。

Request

HTTP GET
https://discover.did.msidentity.com/v1.0/identifiers/did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx

Response

{
    "@context": "https://w3id.org/did-resolution/v1",
    "didDocument":
    {
        "id": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "@context":
        [
            "https://www.w3.org/ns/did/v1",
            {
                "@base": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx"
            }
        ],
        "service":
        [
            {
                "id": "#linkeddomains",
                "type": "LinkedDomains",
                "serviceEndpoint":
                {
                    "origins":
                    [
                        "https://a.example.com/"
                    ]
                }
            },
            {
                "id": "#hub",
                "type": "IdentityHub",
                "serviceEndpoint":
                {
                    "instances":
                    [
                        "https://beta.hub.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
                    ],
                    "origins":
                    []
                }
            }
        ],
        "verificationMethod":
        [
            {
                "id": "#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
                "controller": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpbxxxxxxxxxxxxxxxxxxxxxxxxxx",
                "type": "EcdsaSecp256k1VerificationKey2019",
                "publicKeyJwk":
                {
                    "kty": "EC",
                    "crv": "secp256k1",
                    "x": "Txf25KNr19URFPtMT9eL_idygUfD9y0waAOicXI9aIk",
                    "y": "pqOrwAZSBUrnf7NOQabh4OVKLkf1NUeloBwjIB5DU18"
                }
            }
        ],
        "authentication":
        [
            "#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd"
        ],
        "assertionMethod":
        [
            "#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd"
        ]
    },
    "didDocumentMetadata":
    {
        "method":
        {
            "published": true,
            "recoveryCommitment": "EiCvrbzBIezSVQUPDrS-5BI-kKCnXLHky3bd0857FKa_GA",
            "updateCommitment": "EiBbjggoahMtMGH9c1qpyVosGXtbsz1YYkYqi87mV7OxSg"
        },
        "equivalentId":
        [
            "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w"
        ],
        "canonicalId": "did:ion:EiALbbi7Gmxxxxxxxxxxxxxxxxxxxxxxk37HI_w"
    }
}

受信した DID ResolutionDID DocumentDID Document Metadata の情報が含まれており、
それぞれのプロパティの詳細については、DID Core の Core Properties あたりに記載されています。

上記 DID Document から LinkedDomainsIdentityHub の二つのエンドポイントのが取得できます。

  • LinkedDomains は DID に紐づく、DID 所属先の組織を示すドメインになっております。なぜこのようなパラメータが必要かについては DomainLinkage あたりをご参考ください。
  • IdentityHub のエンドポイントから VC の状態を確認するための Status List を取得できます。この List は VC が Revoke されるときに役に立つですが、Revoke の話については別の記事で書くかと考えています。

もちろん、自分で Wallet を実装する場合、必ずしも MS Verified ID のエンドポイントを利用するわけではなく、Universal Resolver を利用して DID を resolve することも可能なはずです。

(10) MS Verified ID サービスは Web App にコールバックを送信します。

Authenticator が QR コードをスキャンし、Authorization Request を取得したあとに、MS Verified ID サービスは「ユーザーが QR コードをスキャンしたよ」という状態変化を Web App に通知します。

具体的には、手順 (2) にて Web App から MS Verified ID に送信するリクエストの callback.url にある URL に HTTP Post で以下のような Callback リクエストを送信します。

{  
    "requestId":"799f23ea-5241-45af-99ad-cf8e5018814e",  
    "requestStatus":"request_retrieved",  
    "state": "de19cb6b-36c1-45fe-9409-909a51292a9c"
} 

API Reference
https://learn.microsoft.com/ja-jp/azure/active-directory/verifiable-credentials/issuance-request-api#callback-events

Web App が expose しているこの Callback を受け取るためのエンドポイントは野良にたたかれなければ、MS Verified ID に送る Issuance Request の callback.headers.api-key に API Key を設定しとけば、MS Verified ID がこの Callback を Web App に送信する際に、Header に同様な API Key をつけてくれるので、Web App は簡易の API Key 認証を実施できます。

Callback 受信後、ブラウザーから Web App に対する Polling への応答が変わり、ブラウザー上に「QR コードがスキャンされました、Authenticator 側で VC 発行の操作してください。」みたいな文言等が表示される想定です。

(11) Authenticator が Credential Manifest をダウンロードします。

Authorization Request から Credential Manifest を取得するための URL が含まれているので、Authenticator は HTTP GET でこの URL から Credential Manifest を取得します。

実際以下のような HTTP Get が Authenticator から送信されています。
Request

HTTP GET
https://verifiedid.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/contracts/<VC_NAME>

Response

{
   "token": "eyJ..."
}

レスポンスには token しか含まれておらず、中身は JWT 形式の Credential Manifest になります。

Credential Manifest は、(2) の説明とおり、MS Entra Portal に定義されている 表示の定義 & ルールの定義 の内容よって生成されます。

デコードされた Manifest JWT の一例は以下になります(ID Token Hint Attestation の例です)。

{
  "alg": "ES256K",
  "kid": "did:ion:EiALbbi7GmTxxxxxxxHI_w:eyJkZWx0YSI6eyJwYxxxxxxxxxX0dBIn19#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
  "typ": "JWT"
}.{
  "id": "Delos",
  "display": {
    "locale": "en-US",
    "contract": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/contracts/VerifiedCredentialExpert",
    "card": {
      "title": "Verified Credential Expert",
      "issuedBy": "Microsoft",
      "backgroundColor": "#2E4053",
      "textColor": "#ffffff",
      "logo": {
        "uri": "https://xxxxxxxxxxxx.blob.core.windows.net/public/VerifiedCredentialExpert_icon.png",
        "description": "Delos"
      },
      "description": "Welcome to the westworld."
    },
    "consent": {
      "title": "Add Delos Card",
      "instructions": "Delos is offering you a new world."
    },
    "claims": {
      "vc.credentialSubject.firstName": {
        "type": "String",
        "label": "First name"
      },
      "vc.credentialSubject.lastName": {
        "type": "String",
        "label": "Last name"
      }
    },
    "id": "display"
  },
  "input": {
    "credentialIssuer": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/card/issue",
    "issuer": "did:ion:EiALbbi7GmTxxxxxxxHI_w:eyJkZWx0YSI6eyJwYxxxxxxxxxX0dBIn19",
    "attestations": {
      "idTokens": [
        {
          "id": "https://self-issued.me",
          "encrypted": false,
          "claims": [
            {
              "claim": "$.given_name",
              "required": false,
              "indexed": false
            },
            {
              "claim": "$.family_name",
              "required": false,
              "indexed": false
            }
          ],
          "required": false,
          "configuration": "https://self-issued.me",
          "client_id": "",
          "redirect_uri": ""
        }
      ]
    },
    "id": "input"
  },
  "iss": "did:ion:EiALbbi7GmTxxxxxxxHI_w:eyJkZWx0YSI6eyJwYxxxxxxxxxX0dBIn19",
  "iat": 1670485272
}.[Signature]

Authenticator はこの Manifest を受信した後に、以下の作業を実施すると思われます。

  • 正しく署名されているか(公開鍵は iss クレームにある Issuer の DID から取得できます)を検証します。
  • VC を発行する組織のドメインの did-configuration.json を取得するや、Domain Linkage の有効性を検証します。
    などなど。

Manifest に含まれる以下の 3 つの情報について簡単に説明します。

1. VC カードの見た目

JWT の display に VC カードがどのように Wallet 上で表示するか(ログ、表示名、背景色等の見た目情報)が定義されています。

2. Attestation の方式

MS Verified ID サービスが VC を発行する際に、ユーザー Claim (firstname, lastname, nickname, email, etc...)を VC に書き込みます。
Claim の取得方法は定義されている Attestation に従います。

例えば ID Token Attestation を定義した場合、ユーザーは Authenticator 上で AAD B2C 等外部 OP(OpenID Provider)にて認証し、Authenticator が OP が発行された ID Token を MS Verified ID サービスに送信して、MS が ID Token にある Claim を VC に書き込みます。

また、ID Token Hint Attestation では、Web App から MS Verified ID Issuance Request API に送信するリクエストに Claim を直接に記載します。Authenticator 上で別の OP で再度 ID Token を取得しません。

MS Verified ID を利用するにあたって、様々な attestation 方式を選択可能です。詳しくはそれぞれの公開資料をご参照ください。

上記 Manifest の一例は ID Token Hint Attestation になっており、input.attestations.idTokensconfigurationhttps://self-issued.meSIOP (Self-Isued OP) の Issuer Identifier)になっていることを確認できます。

ID Token Attestation の場合、以下のように input.attestations.idTokens に ID Token 取得先となる外部 OP の情報(openid-configuration)が記載されます。

...
"attestations": {
      "idTokens": [
        {
          "id": "https://xxxxxxxxb2c.b2clogin.com/xxxxxxxxb2c.onmicrosoft.com/b2c_1_idp_xxxxxxxx/v2.0/.well-known/openid-configuration", // AAD B2C を利用する場合
          "encrypted": false,
          "claims": [
            {
              "claim": "$.oid",
              "required": false,
              "indexed": false
            },
            {
              "claim": "$.name",
              "required": false,
              "indexed": false
            },
            {
              "claim": "$.given_name",
              "required": true,
              "indexed": false
            },
            {
              "claim": "$.family_name",
              "required": true,
              "indexed": true
            }
          ],
          "required": false,
          "configuration": "https://xxxxxxxxb2c.b2clogin.com/xxxxxxxxb2c.onmicrosoft.com/b2c_1_idp_xxxxxxxx/v2.0/.well-known/openid-configuration",
          "client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
          "redirect_uri": "vcclient://openid",
          "scope": "openid profile email"
        }
      ]
    },
    ...
3. claim mapping に関する設定

MS Verified ID サービスはユーザー クレームを収集して、VC に書き込みます。
VC にどういう Claim を記録するか、その Claim はどこから収集するか(ID Token のどの Claim から収集するか等)も Manifest に定義されています。

(12) ユーザーが Authenticator 上で表示された VC カードの「追加」ボタンをタップします。

ここからは Authenticator が Manifest に定義されている Attestation のフローを実行して MS Verified ID から VC を取得するプロセスに入ります。

Authenticator 上、Manifest に従い(取得しようとする)VC カードのビジュアルを表示します。
Attestation フローによって、さらに外部 OP で認証するためのログイン ボタンも表示したりします。

Attestation 要件を満たした後に、「追加」ボタンが表示され、ユーザーかこのボタンをタップすることで、Authenticator から MS Verified ID に SIOP Authorization Response を送信します。

Attestation フローによって、ID Token の取得の仕組みおよび UI/UX が変わります(後述)が、作成された SIOP レスポンスのスキーマは基本的に変わらないはずです。

ID Token Hint Attestation の場合

ID Token Hint Attestation の場合、VC 発行要求に Web App が MS Verified ID サービスに送信したユーザー Claim が利用されます。

もちろんこの場合 Claim の正当性を担保する責務は Web Apps 側にあります。MS Verified ID は受け取った Claim をもとに ID Token 発行します。

この Attestation 方式を利用する場合、Authenticator は手順 (8) の id_token_hint から受け取った、MS Verified ID が発行した ID Token を (SIOP)Authorization Response の attestation.idTokens に入れて、レスポンスを署名した上で、JWT にエンコードして MS Verified ID サービスに送ります。

SIOP レスポンス一例(Base 64 エンコード前)

{
  "typ": "JWT",
  "alg": "ES256K",
  "kid": "did:ion:EiBtR0YwYDxxxxxxxxxxxxxxxxH89_6Q:eyJkZWx0YSI6eyJwYXRjaxxxxxxxxxxxxxx2TnJlNnVTZyJ9fQ#sign_G8Bzln9MJP"
}.{
  "attestations": {
    "idTokens": {
      "https://self-issued.me": "eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6axxxxxxxxxxxxxxxxxxxxx6kYVhiwhj9988Q"
    }
  },
  "iat": 1670484148,
  "jti": "4A3FC957-A490-4829-A79D-2BBCC12ACF6D",
  "did": "did:ion:EiBtR0YwYDxxxxxxxxxxxxxxxxH89_6Q:eyJkZWx0YSI6eyJwYXRjaxxxxxxxxxxxxxx2TnJlNnVTZyJ9fQ",
  "sub": "v8TYwBsBRxxxxxxxxxxxxxxxu14UKsf6c",
  "sub_jwk": {
    "key_ops": [
      "verify"
    ],
    "use": "sig",
    "x": "f-PuHDWpw5BUnjVR_QiMYlW3SgkPCFB2LwC7tiEsmSw",
    "y": "TlOZVfRGFyEHsgwhX4A4gEm76eNz2OpHMyJFwFVF4o0",
    "alg": "ES256K",
    "kty": "EC",
    "crv": "secp256k1",
    "kid": "sign_G8Bzln9MJP"
  },
  "contract": "https://verifiedid.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/contracts/Delos",
  "aud": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/card/issue",
  "exp": 1670487148,
  "pin": "+KeJWRrY2xxxxxxxxxxxxxxxxxxHwb7U=",
  "iss": "https://self-issued.me"
}.[Signature]
POST
https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/card/issue

eyJ...
ID Token Attestation の場合

ID Token Attestation フローは、ID Token Hint Attestation と大体一緒です。
違いはユーザー Claim を持つ ID Token は外部 OP から取得します。

このフローでは Authenticator は VC カードの表示画面に外部 OP へのログイン ボタンを表示します。ユーザーがこのボタンをタップすると、WebView で外部 OP に遷移され、ユーザーに認証が実行されます。

認証後に Authenticator は OP が発行した ID Token を取得できますので、この ID Token を含めた SIOP レスポンス(JWT)が MS Verified ID に送信されます。

SIOP レスポンス一例(Base 64 エンコード前)

{
  "attestations": {
    "idTokens": {
      "https://xxxxxxxxcomb2c.b2clogin.com/xxxxxxxxcomb2c.onmicrosoft.com/b2c_1_idp_xxxxxxxx/v2.0/.well-known/openid-configuration": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1Nxxxxxxxxxxxxxxxxxxxxxxxxx" // これが外部 OP が発行した ID Token となります
    }
  },
  "iat": 1670587114,
  "jti": "B92BD033-3B8A-4468-A87A-2D54CB6D0FC6",
  "did": "did:ion:did:ion:EiBtR0YwYDxxxxxxxxxxxxxxxxH89_6Q:eyJkZWx0YSI6eyJwYXRjaxxxxxxxxxxxxxx2TnJlNnVTZyJ9fQ",
  "sub": "v8TYwBsBRj89d___-MTZqwolRcrkxQPcBFu14UKsf6c",
  "sub_jwk": {
    "key_ops": [
      "verify"
    ],
    "use": "sig",
    "x": "f-PuHDWpw5BUnjVR_QiMYlW3SgkPCFB2LwC7tiEsmSw",
    "y": "TlOZVfRGFyEHsgwhX4A4gEm76eNz2OpHMyJFwFVF4o0",
    "alg": "ES256K",
    "kty": "EC",
    "crv": "secp256k1",
    "kid": "sign_G8Bzln9MJP"
  },
  "contract": "https://verifiedid.did.msidentity.com/v1.0/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/contracts/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/manifest",
  "aud": "https://beta.did.msidentity.com/v1.0/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/issue",
  "exp": 1670590114,
  "iss": "https://self-issued.me"
},
その他の Attestation の場合

ほかにもいろいろな Attestation フローがありますが、まだそんなに試してない & 流石に本記事には書ききれないので、一旦見送りします。

Self-Issued Attestation と Presentation Attestation なんとなく想像つくし面白そうなので、近いうちに「VC Issuance Attestation 全フローを見る」みたいなのやりたいですね。

(13) Authenticator が Authorization Response を MS Verified ID サービスに送信します。

Authenticator が (12) で作られた SIOP レスポンスを MS Verified ID サービスに送ります。

(14) MS Verified ID が Authenticator に署名済みの VC を送信します。

MS Verified ID サービスが SIOP レスポンスの JWT を受信したあとに、署名を含め SIOP レスポンスの有効性、および attestation.idTokens にある ID Token 等の有効性を検証した上で、Claim Mapping して VC を作成します。

VC 作成後、以下のようなシンプルなレスポンスで JWT 形式の VC を Authenticator に渡します。

{
    "vc": "eyJ..."
}

JWT をデコードしてみると以下の情報が確認でいます。各クレームは Verifiable Credentials Data Model v1.1 の定義に沿ったものとなるはずです。

{
  "alg": "ES256K",
  "kid": "did:ion:EiALbbi7GmxxxxxxxxxxxxHI_w:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxx#792ca9888b1c4cc184fad3b63365f323vcSigningKey-b07dd",
  "typ": "JWT"
}.{
  "vc": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1"
    ],
    "type": [
      "VerifiableCredential",
      "VerifiedCredentialExpert"
    ],
    "credentialSubject": {
      "firstName": "Peichao",
      "lastName": "Yu"
    },
    "credentialStatus": {
      "id": "urn:uuid:cca8bd0a-83c2-4ae1-9f43-e99943cdfa5c?bit-index=12",
      "type": "RevocationList2021Status",
      "statusListIndex": 12,
      "statusListCredential": "did:ion:EiALbbi7GmxxxxxxxxxxxxHI_w:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxx?service=IdentityHub&queries=W3sibWV0aG9kIjoiQ29sbGVjdGlvbnNRdWVyeSIsInNjaGVtYSI6Imh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSIsIm9iamVjdElkIjoiY2NhOGJkMGEtODNjMi00YWUxLTlmNDMtZTk5OTQzY2RmYTVjIn1d"
    },
    "exchangeService": {
      "id": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredential/card/exchange",
      "type": "PortableIdentityCardServiceExchange2020"
    }
  },
  "jti": "urn:pic:2cd7dd2232ae49afa0f852ceeefce60e",
  "iss": "did:ion:EiALbbi7GmxxxxxxxxxxxxHI_w:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxx",
  "sub": "did:ion:EiBtR0YwYDcxxxxxxxxxxxQH89_6Q:eyJkZWx0YSI6eyJxxxxxxxxxxxxxx",
  "iat": 1670500048,
  "exp": 1673092049
}.[Signature]

これで素敵な VC カードがあなたの Wallet (Authenticator アプリ) に保存されます。

(15) Authenticator から MS Verified ID に issuance_successful の通知を送信します。

Authenticator が VC を正しく取得したあとに、MS Verified ID サービスに以下のような「VC 受け取ったよ」的な通知を送ります。

Request

POST https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/issuance

{
  "state": "xxxxxxxxxxxxxxxxxxxxxxxxx",
  "code": "issuance_successful"
}

Response

202 Accepted

このやり取りは MS にドキュメントされていないですが、同様に Wallet を自前で作らなければ、このやり取りを意識する必要がないでしょう。

MS が提供する Wallet SDK が GA になりましたら、おそらく SDK のドキュメントとともに、このあたりの API のドキュメントもちゃんと整備してくれる思います。

(16) MS Verified ID が Web App の Callback エンドポイントに「VC 発行されたよ」のお知らせを送信します。

Web App 側に VC カードの発行が成功したことをまだ伝えていないので、最後に MS Verified ID から Web App に Callback で状態変更を通知します。

ここで送信されたリクエストは手順 (10) と同じものとなります。違いは requestStatus が issuance_successful になるだけです。

(17) Web ブラウザーが Polling で状態変更を取得し、ユーザーに知らせます。

VC 発行成功みたいな文言がブラウザー上に表示され、VC 発行フローが終了となります。

終わりに

Microsoft Verified ID サービスを利用して、VC 発行フローの舞台裏を簡単にまとめてみました。
Attestation はすべて試したわけではないので不完全な部分もありますが、参考になりますと幸いです。

VC (VP) 検証フローについては、以下の続編記事にまとめましたので、ご参考いただければ幸いです。

Microsoft Entra Verified ID の動きをみてみた。 検証編
https://zenn.dev/nerocrux/articles/32a0b1f8d7f877

それでは、メリークリスマス(?)

Discussion